cURL PHP SSL - 无法验证服务器端,但并非总是如此

Posted

技术标签:

【中文标题】cURL PHP SSL - 无法验证服务器端,但并非总是如此【英文标题】:cURL PHP SSL - Unable to verify server side, but not always 【发布时间】:2015-07-08 18:01:01 【问题描述】:

我在使用 Mandrill php API 时遇到了一些麻烦

SSL certificate problem: unable to get local issuer certificate

我在网上挖掘了一些关于为 cURL 配置 cacarts 文件的信息。 所以我有来自http://curl.haxx.se/docs/caextract.html 的当前证书提取,并且还在PHP.ini 中配置了该文件的(VALID)路径

curl.cainfo=some\local\path\\certs\cacert.pem

现在我正在测试多个 HTTPS 网站(测试的 src here)

$this->nxs_cURLTest("https://mandrillapp.com/api/1.0/users/ping.json", "TestApiCALL", "Mandrill API CERT");
$this->nxs_cURLTest("https://www.google.com/intl/en/contact/", "HTTPS to Google", "Mountain View, CA");
$this->nxs_cURLTest("http://www.google.com/intl/en/contact/", "HTTP to Google", "Mountain View, CA");
$this->nxs_cURLTest("https://www.facebook.com/", "HTTPS to Facebook", 'id="facebook"');
$this->nxs_cURLTest("https://www.linkedin.com/", "HTTPS to LinkedIn", 'link rel="canonical" href="https://www.linkedin.com/"');
$this->nxs_cURLTest("https://twitter.com/", "HTTPS to Twitter", 'link rel="canonical" href="https://twitter.com/"');
$this->nxs_cURLTest("https://www.pinterest.com/", "HTTPS to Pinterest", 'content="Pinterest"');
$this->nxs_cURLTest("https://www.tumblr.com/", "HTTPS to Tumblr", 'content="Tumblr"');

并得到不一致的结果,例如:

Testing ... https://mandrillapp.com/api/1.0/users/ping.json - https://mandrillapp.com/api/1.0/users/ping.json
....TestApiCALL - Problem

SSL certificate problem: unable to get local issuer certificate
Array
(
    [url] => https://mandrillapp.com/api/1.0/users/ping.json
    [content_type] => 
    [http_code] => 0
    [header_size] => 0
    [request_size] => 0
    [filetime] => -1
    [ssl_verify_result] => 0
    [redirect_count] => 0
    [total_time] => 0.14
    [namelookup_time] => 0
    [connect_time] => 0.062
    [pretransfer_time] => 0
    [size_upload] => 0
    [size_download] => 0
    [speed_download] => 0
    [speed_upload] => 0
    [download_content_length] => -1
    [upload_content_length] => -1
    [starttransfer_time] => 0
    [redirect_time] => 0
    [certinfo] => Array
        (
        )

    [primary_ip] => 54.195.231.78
    [primary_port] => 443
    [local_ip] => 192.168.2.142
    [local_port] => 63719
    [redirect_url] => 
)

There is a problem with cURL. You need to contact your server admin or hosting provider.Testing ... https://www.google.com/intl/en/contact/ - https://www.google.com/intl/en/contact/
....HTTPS to Google - OK
Testing ... http://www.google.com/intl/en/contact/ - http://www.google.com/intl/en/contact/
....HTTP to Google - OK
Testing ... https://www.facebook.com/ - https://www.facebook.com/
....HTTPS to Facebook - OK
Testing ... https://www.linkedin.com/ - https://www.linkedin.com/
....HTTPS to LinkedIn - OK
Testing ... https://twitter.com/ - https://twitter.com/
....HTTPS to Twitter - OK
Testing ... https://www.pinterest.com/ - https://www.pinterest.com/
....HTTPS to Pinterest - Problem

SSL certificate problem: unable to get local issuer certificate
Array
(
    [url] => https://www.pinterest.com/
    [content_type] => 
    [http_code] => 0
    [header_size] => 0
    [request_size] => 0
    [filetime] => -1
    [ssl_verify_result] => 0
    [redirect_count] => 0
    [total_time] => 0.078
    [namelookup_time] => 0
    [connect_time] => 0.016
    [pretransfer_time] => 0
    [size_upload] => 0
    [size_download] => 0
    [speed_download] => 0
    [speed_upload] => 0
    [download_content_length] => -1
    [upload_content_length] => -1
    [starttransfer_time] => 0
    [redirect_time] => 0
    [certinfo] => Array
        (
        )

    [primary_ip] => 23.65.117.124
    [primary_port] => 443
    [local_ip] => 192.168.2.142
    [local_port] => 63726
    [redirect_url] => 
)

There is a problem with cURL. You need to contact your server admin or hosting provider.Testing ... https://www.tumblr.com/ - https://www.tumblr.com/
....HTTPS to Tumblr - OK

如您所见,总体 SSL 配置正常,但出于某种原因需要 2 次调用

    https://www.pinterest.com/ https://mandrillapp.com/api/1.0/users/ping.json

我遇到了同样的错误。上面的链接在浏览器中打开得很好,他们的 CA 链证书也是有效的。这可能是什么原因?

编辑:

我花了大约 6 个小时来尝试解决这个问题,并在 SO 上发布问题大约 2 分钟后找到了关于正在发生的事情的线索。 所以我在http://curl.haxx.se/docs/caextract.html 上又读了一次关于那里提供的摘录的信息。什么让我眼花缭乱(现在,但我以前读过它还不到 100 次)

RSA-1024 已移除

大约在 2014 年 9 月上旬,Mozilla 从 仍在使用 RSA 1024 位密钥的 CA 包中的证书。这 如果出现以下情况,可能会导致 TLS 库难以验证某些站点 有问题的库不能正确支持“路径发现”,因为 根据 RFC 4158。(包括 OpenSSL 和 GnuTLS。)

我们在清理之前转换的最后一个 CA 包:一个较旧的 来自 github 的 ca-bundle。

所以我从“清理之前”中拍摄了一个疲惫的小家伙 - 现在所有测试都通过了! 所以另一个问题是 - 是关于我的机器上的过时软件,如 OpenSSL、PHP、cURL 等,还是 在测试中失败的站点具有过时的证书格式到 RFC 4158,这就是造成麻烦的原因?

【问题讨论】:

【参考方案1】:

所以另一个问题是 - 是关于我的机器上的过时软件,如 OpenSSL、PHP、cURL 等,还是测试失败的网站根据 RFC 4158 具有过时的证书格式和那是什么造成了麻烦?

这些可能都没有。删除的证书在旧 Root-CA 中只有一个 1024 位密钥。这些证书不知何故被更新的证书取代,但不在同一个地方,即如果您经常有多个可能的信任路径:

host-cert -> intermediate.1 -> 2048bit intermediate.2 -> 1024bit root-CA
host-cert -> intermediate.1 -> 2048bit new root

2048bit new root 的公钥与2048bit intermediate.2 的公钥相同,因此intermediate.1 的签名仍将匹配,从而链验证将成功。但是,虽然大多数 TLS 堆栈都试图找到最好的链,但 OpenSSL 坚持最长的链。这意味着如果服务器发送链

host-cert -> intermediate.1 -> 2048bit intermediate.2

那么 OpenSSL 将坚持找到一个根 CA 签名 intermediate.2,即使它有一个根 CA 签名 intermediate.1(即2048bit new root)。如果旧的1024bit root-CA 不再在信任存储中,则验证将失败。如果相反,服务器只发送

host-cert -> intermediate.1

然后验证将通过2048bit new root 成功。但是很多服务器仍然会发送更长的链来保持与没有2048bit new root的旧客户端的兼容性。

都非常丑陋,2015 中的 bug was reported in 2012 和 again。 OpenSSL 1.0.2(新发布)至少有一个选项X509_V_FLAG_TRUSTED_FIRST 来解决这个问题,OpenSSL git 中有一些变化似乎可以解决这个问题,但不清楚它们是否将每个向后移植到 1.0.2 或更低版本:(

现在您最好将旧的 1024 位证书保存在信任库中。

【讨论】:

以上是关于cURL PHP SSL - 无法验证服务器端,但并非总是如此的主要内容,如果未能解决你的问题,请参考以下文章

验证 curl 是不是使用 TLS

php curl常见错误:SSL错误、bool(false)

php7 curl返回false error返回空串

使用带有 SSL 证书的 PHP cURL 时出错

PHP CURL CURLOPT_SSL_VERIFYPEER 被忽略

请教一个PHP CURL的POST提交遇到的问题