大家早上好,
上周,我决定运行命令来升级 14.04 Server 上的软件包,以确保我已修补最近发现的 Bash 漏洞。根据此处的信息 (http://www.ubuntu.com/usn/usn-2362-1/)我运行了 apt-get dist-upgrade。作为参考,我运行了 apt-get update、apt-get dist-upgrade,然后运行了 apt-get upgrade,以尝试并确保我已将所有内容更新到最新版本(尽管我经常运行 apt-get upgrade)。
成功完成此操作后,我发现我的许多 Perl 脚本不再起作用。作为参考,我使用此服务器为 Nagios 监控我所有的其他服务器。现在失败的问题脚本都通过 https 连接到系统,登录主机并查询各种信息。
升级之前,我可以在每个 Perl 脚本中添加一行,使其忽略 SSL:
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0 }
但是,升级后,这似乎没有影响,并且所有脚本都失败,因为它们无法验证 SSL 证书(所有自签名)。
以下是我所看到的一些片段:
脚本执行:
nagios@nagios:/usr/local/nagios/libexec$ ./check_esx.pl -H 192.168.22.18 -u root -p password -l cpu
CHECK_ESX.PL CRITICAL - Can't connect to 192.168.22.18:443 (certificate verify failed)
LWP::Protocol::https::Socket: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed at /usr/share/perl5/LWP/Protocol/http.pm line 41.
这个特定的 Perl 脚本利用“VMware Infrastructure (VI) Perl Toolkit”来运行。我调用的脚本 check_esx.pl 可用这里
这是文件 http.pm 中上述错误所引用的行附近的一个片段;第 41 行是“die”行。
sub _new_socket
{
my($self, $host, $port, $timeout) = @_;
local($^W) = 0; # IO::Socket::INET can be noisy
my $sock = $self->socket_class->new(PeerAddr => $host,
PeerPort => $port,
LocalAddr => $self->{ua}{local_address},
Proto => 'tcp',
Timeout => $timeout,
KeepAlive => !!$self->{ua}{conn_cache},
SendTE => 1,
$self->_extra_sock_opts($host, $port),
);
unless ($sock) {
# IO::Socket::INET leaves additional error messages in $@
my $status = "Can't connect to $host:$port";
if ($@ =~ /\bconnect: (.*)/ ||
$@ =~ /\b(Bad hostname)\b/ ||
$@ =~ /\b(certificate verify failed)\b/ ||
$@ =~ /\b(Crypt-SSLeay can't verify hostnames)\b/
) {
$status .= " ($1)";
}
die "$status\n\n$@";
}
# perl 5.005's IO::Socket does not have the blocking method.
eval { $sock->blocking(0); };
$sock;
}
所以我想我在这里寻找的是以下两种情况之一
要么:(A) 是否有新的/更好的/更正确的方法让 Perl 忽略 SSL 证书?或 (B) 是否有办法将自签名 SSL 证书从另一台主机导入 Ubuntu,以便 Perl 脚本能够识别并信任它?或者:(B-2) 是否有办法让 Ubuntu 识别我的 Windows 活动目录证书颁发机构,以便我可以从我的 CA 向相关系统颁发 SSL 证书,并让 Perl 脚本识别它?
提前谢谢大家!
答案1
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0
这是 LWP 中的一个错误(CVE-2014-3230),已在较新版本中修复。PERL_LWP_SSL_VERIFY_HOSTNAME 仅用于省略验证证书中的主机名,而不是证书链。但是,由于您使用的是自签名证书链,因此验证将失败。
此选项仅用于从旧 Crypt::SSLeay 后端迁移到新 IO::Socket::SSL 后端。Crypt::SSLeay 不支持主机名验证(因此容易受到中间人攻击),而 IO::Socket::SSL 则支持。对于 LWP 版本 6,默认后端是 IO::Socket::SSL。
要完全禁用证书集验证SSL_verify_mode => SSL_VERIFY_NONE
(您需要use IO::Socket::SSL
访问 SSL_VERIFY_NONE 常量,或者直接使用 0),请在 LWP 的 ssl_opts 中执行此操作。没有环境变量可以执行此操作。
例子:
use LWP::UserAgent;
use IO::Socket::SSL;
my $ua = LWP::UserAgent->new(..., ssl_opts => { SSL_verify_mode => SSL_VERIFY_NONE });
$ua->get(...); # or $ua->post(...) or $ua->request(...)
不幸的是,我看不到您引用的脚本中使用 LWP 的地方,所以我不知道在哪里可以修复它。
至于您的选项 B:
(B) 有没有办法将自签名 SSL 证书从另一台主机导入 Ubuntu,以便 Perl 脚本能够识别并信任它?或者:(B-2) 有没有办法让 Ubuntu 识别我的 Windows 活动目录证书颁发机构,以便我可以从我的 CA 向相关系统颁发 SSL 证书,并让 Perl 脚本识别它?
您应该能够使用环境变量 PERL_LWP_SSL_CA_FILE 来指定您接受为受信任的 CA 或自签名证书的文件。
答案2
我认为这是一个 perl 版本问题,请检查您之前使用哪个 perl 版本来运行该脚本。
我确信的是,Ubuntu 会安装每个软件的最新稳定版本。例如,如果你有一个在 ubuntu 12.04 上运行的 python3 脚本,它可能无法在 ubuntu 14.04 上运行,原因是前者有 python 3.2 版本,而后者有 python 3.4 版本。
我认为您的 perl 脚本也遇到了同样的情况,请检查 perl 版本和新版本的发行说明。