WWW::Mechanize https get 的 SSL 连接尝试失败

WWW::Mechanize SSL connect attempt failed for https get

我正在尝试使用 WWW::Mechanize 检索网页,但因 SSL 连接错误而失败。我该如何解决这个问题?我是 运行 ActivePerl 5.20.2 Windows 10 x64。

这是我执行的脚本:

perl -MIO::Socket::SSL=debug4 -MWWW::Mechanize -e 'WWW::Mechanize->new()->get("https://fundresearch.fidelity.com/mutual-funds/fees-and-prices/316343201")'

输出结果如下:

DEBUG: .../IO/Socket/SSL.pm:2649: new ctx 98842176
DEBUG: .../IO/Socket/SSL.pm:562: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:564: socket connected
DEBUG: .../IO/Socket/SSL.pm:586: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:619: using SNI with hostname fundresearch.fidelity.com
DEBUG: .../IO/Socket/SSL.pm:654: request OCSP stapling
DEBUG: .../IO/Socket/SSL.pm:673: set socket to non-blocking to enforce timeout=180
DEBUG: .../IO/Socket/SSL.pm:686: call Net::SSLeay::connect
DEBUG: .../IO/Socket/SSL.pm:689: done Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:699: ssl handshake in progress
DEBUG: .../IO/Socket/SSL.pm:709: waiting for fd to become ready: SSL wants a read first
DEBUG: .../IO/Socket/SSL.pm:729: socket ready, retrying connect
DEBUG: .../IO/Socket/SSL.pm:686: call Net::SSLeay::connect
DEBUG: .../IO/Socket/SSL.pm:2552: did not get stapled OCSP response
DEBUG: .../IO/Socket/SSL.pm:2505: ok=0 cert=102327360
DEBUG: .../IO/Socket/SSL.pm:689: done Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:692: SSL connect attempt failed

DEBUG: .../IO/Socket/SSL.pm:692: local error: SSL connect attempt failed error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:695: fatal SSL error: SSL connect attempt failed error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
DEBUG: .../lib/Net/HTTPS.pm:69: ignoring less severe local error 'IO::Socket::IP configuration failed', keep 'SSL connect attempt failed error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed'
DEBUG: .../IO/Socket/SSL.pm:2682: free ctx 98842176 open=98842176
DEBUG: .../IO/Socket/SSL.pm:2687: free ctx 98842176 callback
DEBUG: .../IO/Socket/SSL.pm:2694: OK free ctx 98842176
Error GETing https://fundresearch.fidelity.com/mutual-funds/fees-and-prices/316343201: Can't connect to fundresearch.fidelity.com:443 at -e line 1.

我能够使用 curl 成功检索网页。

Works For Me™ IO::Socket::SSL 2.052、WWW::Mechanize 1.86 和 Net::SSLeay 1.80。我怀疑您需要升级 Net::SSLeay。我建议升级所有这些。

差异从这里开始。您认为证书不正确。

DEBUG: .../IO/Socket/SSL.pm:2552: did not get stapled OCSP response
DEBUG: .../IO/Socket/SSL.pm:2505: ok=0 cert=102327360

但我的确实如此。更详细的输出是因为我升级了 Net::SSLeay.

DEBUG: .../IO/Socket/SSL.pm:2722: did not get stapled OCSP response
DEBUG: .../IO/Socket/SSL.pm:2675: ok=1 [2] /C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2009 Entrust, Inc. - for authorized use only/CN=Entrust Root Certification Authority - G2/C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2009 Entrust, Inc. - for authorized use only/CN=Entrust Root Certification Authority - G2

该流程由 Net::SSLeay 处理。您的 Net::SSLeay 版本可能与您的 OpenSSL C 库不兼容。自从 ActivePerl 5.20.2 出来以来已经有a lot of fixes for compatibility with OpenSSL 1.1

TL;DR: 升级 Perl 或至少升级 Mozilla::CA 模块或使用 SSL_ca_file 和你自己的信任库。


我怀疑问题是因为您使用的是旧版本的 Perl,特别是此 Perl 中包含的 Mozilla::CA 模块的旧版本。查看此站点的证书链(例如 SSLLabs),您会发现它如下所示:

[0] CN=fundresearch.fidelity.com
[1] CN=Entrust Certification Authority - L1K
[2] CN=Entrust Root Certification Authority - G2   -- selfsigned

此信任链中的最后一个证书是自签名的,即对该证书的信任来自证书本身。这是服务器的明显错误配置,这就是为什么在验证信任链时忽略此证书的原因。

CN=Entrust Certification Authority - L1K 的颁发者 CA 是 CN=Entrust Root Certification Authority - G2,即正是服务器发送的证书,但被忽略了,因为不应该仅基于服务器发送的信任。这意味着本地信任库中需要有此根 CA 的实例。

现代浏览器和 OS 在信任库中拥有此 CA,这就是您可以使用浏览器访问此站点的原因。但是,WWW::Mechanize(基于 LWP::UserAgent)不使用系统信任库(至少在 Windows 上)。相反,信任库由 Mozilla::CA 模块提供,该模块不时从 Mozilla(即 Firefox)获取信任库的副本。

根据您的 Perl 发行版版本,您可能使用 Mozilla::CA 的 20141217 版本。此版本尚未将 CA Entrust Root Certification Authority - G2 列为受信任的。此 CA 仅包含在下一个 version 20150826 中。由于 CA 不被认为是可信的,因此验证将失败。

有几个可能的修复。

  • 一个是升级Perl的版本。这可能是最好的选择,因为这还包括在处理多个可能的信任路径时对 OpenSSL 的修复 - 这是您可能 运行 在其他站点遇到的问题(有关详细信息,请参阅 )。
  • 另一种方法是只升级 Mozilla::CA 模块。但是,如果您仍然使用旧的 Perl,而上述 OpenSSL 问题未得到修复,这实际上可能会导致某些站点出现问题。
  • 或者您可以将 the missing certificate 添加到您的 cacert.pem(Mozilla::CA 提供的)。
  • 最后,您可以使用 ssl_optsSSL_ca_file 来设置您自己的信任库,其中包括丢失的 CA 证书。