13

我使用 cURL 在 WordPress 插件中验证 PayPal 交易。最近我开始收到关于用户无法完成购买过程的错误报告,因为无法验证交易。我将错误追踪到:

SSL certificate problem, verify that the CA cert is OK. Details: 
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

CURLOPT_CAINFO我在 StackOverflow 中发现了很多与同一问题相关的问题,其中大多数人说解决方案是使用cURL 的选项提供一束 CA。我下载了http://curl.haxx.se/ca/cacert.pem的最新版本(于 2012 年 6 月 28 日转换)插件,目前随该插件一起发布。这解决了我收到的大部分问题。

现在的问题是,我刚刚收到另一份付款失败的报告,而且错误是一样的:SSL certificate problem, verify that the CA cert is OK.。有趣的是,现在的解决方案是删除CURLOPT_CAINFO选项。我想知道这是否有解释。我认为使用更新的 CA 包(例如我下载的包)是一种通用解决方案,但似乎并非如此。

这种问题的一般解决方案是什么?什么可以解释使用更新的 CA 包导致 SSL 证书问题,而不是修复它们?

这是 cURL 配置:

<?php
    $ch = curl_init("https://www.paypal.com/cgi-bin/webscr");
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_VERBOSE, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $content);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
?>

更新:www.paypal.com 的证书由 VeriSign 签名。证书层次结构(如 Firefox 中所示)是:

  • VeriSign 3 类公共主要证书颁发机构 - G5
  • VeriSign Class 3 扩展验证 SSL CA
  • www.paypal.com

我可以确认VeriSign 3 类公共主要证书颁发机构的证书 - G5包含在我正在使用的http://curl.haxx.se/ca/cacert.pem版本中。

谢谢你的帮助。

4

2 回答 2

11

如果您遇到此问题,请不要有人建议的那样禁用对等和主机验证。

这将使您的通信容易受到潜在的中间人攻击,从而破坏了使用 SSL 的初衷。

这个问题的一个可能的解释是设置你的CURLOPT_CAINFO(特别是不正确的证书路径 - 我会仔细检查这个)覆盖你服务器上的默认路径。

删除设置后,它会恢复为默认值(可以在 PHP 中设置)。

要记住的另一件事是,这CURLOPT_CAINFO是一条绝对路径。

于 2014-01-21T03:44:48.100 回答
4

看到这个网址

http://davidwalsh.name/php-ssl-curl-error

或尝试一下

$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,'https://thirdparty.com/token.php'); //not the actual site
curl_setopt($ch,CURLOPT_TIMEOUT,60);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,'customer_id='.$cid.'&password='.$pass);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,true); 
curl_setopt($ch,CURLOPT_CAINFO,'mozilla.pem'); /* fixed! */
$result = curl_exec($ch);
if(empty($result)) { /* error: nothing returned */ } else { /* success! */ }
curl_close($ch);
于 2012-09-06T17:18:47.420 回答