SSL/TLS 握手中出现问题

Posted

技术标签:

【中文标题】SSL/TLS 握手中出现问题【英文标题】:A problem occurred somewhere in the SSL/TLS handshake 【发布时间】:2012-04-04 04:26:28 【问题描述】:

我在我的开发服务器上遇到了问题,其中 cURL 虽然可以完美地与任何 HTTP 一起工作,但不能与任何 HTTPS 一起正常工作——即使是具有不同协议的完全相同的资源(为了测试我一直在请求 google.com使用 HTTP 和 HTTPS)。

返回的 cURL 错误是 35:

我已经梳理了网络和 SO 的解决方案,所有这些都是将 CURLOPT_SSL_VERIFYPEER 设置为 false,这不会改变任何内容,或者下载证书文件并将 CURLOPT_CAINFO 设置为其路径,这也不会改变任何内容。

在设置证书时,我按照this tutorial 和this tutorial 的说明,尝试为我请求的资源下载证书,并下载证书包。

我还尝试将 CURLOP_PORT 显式设置为 443。为了我的问题的彻底性,我设置的其他选项是 CURLOPT_VERBOSE=true、CURLOPT_RETURNTRANSFER=true 和 CURLOPT_SSL_VERIFYHOST=2(我已经尝试了 1 和 2 的每种组合VERIFYPEER 真假)。我还在phpinfo() 中确保我拥有 OpenSSL 并且它已启用。

我使用了很多旧代码,它们在我的上一个生产服务器上运行良好,所以这段代码以前也可以运行。但是那个主机是共享主机,我不知道那里的大部分配置。

【问题讨论】:

您访问的是同一个 URL 吗?当我遇到这个问题时,你已经完成了大部分相同的研究。 我同时使用了 http://www.google.com,效果很好;和 https://www.google.com,但没有。 @Spezied,如果提供的答案回答了您的问题,您能否选择它作为您的答案,以便可以关闭问题?谢谢。 它没有回答这个问题,因为我在问题中明确指出这正是我在 SO 和 Internet 上的其他地方找到的不令人满意的答案。从那以后,我得出结论,它一定不能在 PHP 中修复。 PHP或我的扩展或其他东西有问题。虽然我仍然不知道如何解决这个问题。我会四处看看。还是谢谢你。 【参考方案1】:

Curl 没有内置的根证书(就像大多数现代浏览器一样)。您需要明确地将其指向一个 cacert.pem 文件:

  curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cert/file/cacert.pem');

没有这个,curl 无法验证通过 ssl 发回的证书。每次在 curl 中使用 SSL 时都可以使用相同的根证书文件。

您可以在此处获取 cacert.pem 文件:http://curl.haxx.se/docs/caextract.html

【讨论】:

为什么不直接使用 --insecure 标志呢?有吗? @Pacerier 将 CURLOPT_SSL_VERIFYPEER 设置为 false 正是 --insecure 标志在命令行上的作用。如果您关心目标服务器的真实性,您也不想这样做 它没有用。而CURLOPT_SSL_VERIFYPEERfalse 可以。 @n8bar 那么你做错了什么。是的,禁用 SSL 验证总是有效的,但只有在您不关心目标服务器的真实性时才再次这样做——这不是一个明智的安全选择。 不工作,上面的代码结果为空。请提出其他建议【参考方案2】:

这个怎么样。它获取可能是 HTTPS Google 主页的内容。 (由于我禁用了证书验证,我无法真正知道这是真正的 Google 主页。)它应该可以解决问题。

<?PHP

// connect via SSL, but don't check cert
$handle=curl_init('https://www.google.com');
curl_setopt($handle, CURLOPT_VERBOSE, true);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
$content = curl_exec($handle);

echo $content; // show target page
?>

【讨论】:

看我上面的回答,忽略证书不是最好的选择。 这是不安全的。不要这样做。始终验证对等方和主机。查看其他答案。 @马特。取决于你在做什么。为金融移动重要的东西,当然要验证 HTTPS。从零售商网站上抓取鞋履品牌...... MITM 应该不是问题。显然要考虑问题的背景。 正确答案如上所述。当您只需将 cacert.pem 文件复制到您的项目并确保连接安全时,为什么要使用它。它确实需要一秒钟。 这确实是不安全的,但是,它可以用于不实际传输敏感数据的测试目的。只是不要在生产中使用它。【参考方案3】:

查看您的操作系统是否包含证书目录。如果是这样,那么通常已经包含所需的 CA 证书。例如,在 Ubuntu 上,它通常是 /etc/ssl/certs。如果该目录存在,设置CA路径参数:

curl_setopt($ch, CURLOPT_CAPATH, '/etc/ssl/certs');

或者,您可以引用单个 CA 证书文件。在您的项目中包含一个 cacert.pem 文件或将其安装在您的服务器上。从受信任的来源下载,例如cacert.org。对于单个文件,不要设置 CAPATH,而只设置 CAINFO:

curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem');

关闭对等和主机验证是解决实际问题的一种快速但不安全的解决方法。这些功能的存在是有充分理由的:因此您可以通过第 3 方相信您正在连接的系统是您所期望的。

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

【讨论】:

【参考方案4】:
var_dump( curl_error($ch) );

会告诉你错误。这可能是不同的原因。

【讨论】:

我不确定这如何回答这个问题。这可能是一个很好的建议,但 OP 已经知道错误消息。这不会对该线程添加任何内容。 虽然这对我来说是有用的信息 - 所以有一点进退两难的局面,但我想没有什么是不可能不相处的:)

以上是关于SSL/TLS 握手中出现问题的主要内容,如果未能解决你的问题,请参考以下文章

SSL/TLS 链接的建立/握手

ftp_nlist():data_accept:SSL / TLS握手失败

对 Google Chrome 浏览器中的 SSL/TLS 握手进行故障排除

TLS握手协议

SSL/TLS 握手优化详解

Https加密原理:SSL/TLS四次握手过程(转载)