如何使用 LWP::UserAgent 接受自签名证书

Posted

技术标签:

【中文标题】如何使用 LWP::UserAgent 接受自签名证书【英文标题】:How to accept self-signed certificates with LWP::UserAgent 【发布时间】:2018-05-19 15:15:59 【问题描述】:

我正在尝试设置使用 HTTPS 的 node.js 服务器。然后我将在 Perl 中编写一个脚本来向服务器发出 HTTPS 请求并测量往返的延迟。

这是我的 node.js:

var express = require('express');
var https = require('https');
var fs = require('fs');

var key = fs.readFileSync('encrypt/rootCA.key');
var cert = fs.readFileSync('encrypt/rootCA.pem');

// This line is from the Node.js HTTPS documentation.
var options = 
  key: key,
  cert: cert
;

https.createServer(options, function (req, res) 
    res.writeHead(200);
    res.end("hello world - https\n");
).listen(8088);

密钥/证书生成如下:

openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem

这是我的 Perl 脚本:

#!/usr/bin/perl
use LWP::UserAgent;


my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET => 'https://127.0.0.1:8080');
my $res = $ua->request($req);

if ($res->is_success) 
  print $res->as_string;
 else 
  print "Failed: ", $res->status_line, "\n";

返回错误:

Failed: 500 Can't verify SSL peers without knowing which Certificate Authorities to trust

node.js 文档描述了如何设置 HTTPS 服务器,但对生成主证书和中间证书的内容含糊不清。

https://medium.com/netscape/everything-about-creating-an-https-server-using-node-js-2fc5c48a8d4e

【问题讨论】:

所以您的问题实际上是“如何配置 LWP::UserAgent 以接受 HTTPS 的自签名证书?” 实际上是的。你知道怎么做吗? 我明白了。感谢@amon 为我指明了正确的方向 【参考方案1】:

此类问题的典型答案是完全禁用证书验证。但是,这是完全不安全的,并且基本上禁用了 HTTPS 提供的大部分保护。 如果验证被完全禁用,中间人攻击者可以使用任意证书拦截连接并嗅探和修改数据。因此,不要这样做。

处理此类证书的正确方法是将这些证书添加为受信任的。这可以通过SSL_ca_file 参数来完成:

my $ua = LWP::UserAgent->new;
$ua->ssl_opts(SSL_ca_file => 'rootCA.pem');
$ua->get('https://127.0.0.1:8080');

通过将自签名服务器证书明确信任为 CA,它将不再抛出“证书验证失败”。

但是,除非您的服务器证书实际颁发给“127.0.0.1”,否则您现在将收到“主机名验证失败”,因为证书的主题与 URL 的域不匹配。这可以通过设置预期的主机名来解决:

my $ua = LWP::UserAgent->new;
$ua->ssl_opts(
    SSL_ca_file => 'rootCA.pem',
    SSL_verifycn_name => 'www.example.com',
);
$ua->get('https://127.0.0.1:8080');

请注意,SSL_ca_file 需要自签名证书将 CA 标志设置为 true,即该证书是可用于颁发其他证书的 CA 证书。如果您的证书不是这种情况,或者您只想接受特定证书,无论它是否已过期、被吊销、与主机名不匹配等,您都可以使用证书的指纹进行验证。

my $ua = LWP::UserAgent->new;
$ua->ssl_opts(SSL_fingerprint => 'sha1$9AA5CFED857445259D90FE1B56B9F003C0187BFF')
$ua->get('https://127.0.0.1:8080');

这里的指纹和openssl x509 -noout -in rootCA.pem -fingerprint -sha1一样,只是前面加了算法(sha1$...),去掉了冒号。

【讨论】:

【参考方案2】:

要使 LWP::UserAgent 忽略服务器证书,请使用以下配置:

my $ua = LWP::UserAgent->new;
$ua->ssl_opts(
    SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, 
    verify_hostname => 0
);

【讨论】:

这不仅仅是接受自签名证书。这是接受 any 证书,因此 使连接对中间攻击中的任意人开放 @SteffenUllrich 这就是接受自签名证书的作用,是的。 @duskwuff: “这就是接受自签名证书的作用,是的。” - 不,您可以以安全的方式接受特定的自签名证书,即无需完全禁用验证,从而接受此处所做的任意证书。这也很容易。看我的回答。

以上是关于如何使用 LWP::UserAgent 接受自签名证书的主要内容,如果未能解决你的问题,请参考以下文章

为啥 LWP::UserAgent 是通过 require LWP::UserAgent 而不是使用 LWP::UserAgent 导入的?

LWP::UserAgent介绍2

Perl LWP::UserAgent 错误处理 UTF-8 响应

未通过 https 使用 LWP::UserAgent get() 获取预期内容

LWP::UserAgent介绍1

perl LWP::UserAgent获取源码与响应