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

Posted

技术标签:

【中文标题】使用带有 SSL 证书的 PHP cURL 时出错【英文标题】:Error using PHP cURL with SSL certificates 【发布时间】:2010-10-18 09:11:45 【问题描述】:

我正在尝试使用 cURL 编写一个 php 脚本,该脚本可以通过使用 SSL 证书的页面以及用户名和密码来授权用户,但我似乎无法通过 SSL 证书阶段。

在这种情况下,很遗憾,curl_setopt($handle, CURLOPT_VERIFYPEER, 0) 不是一个选项。证书是身份验证的必需部分,否则我会收到this other similar SO post 中提到的错误。

我已经用 cURL 尝试了一些命令行运行:

> curl --url https://website

这将返回 (60) SLL certificate problem 错误。如果我调整命令以包含 --cacert 选项:

> curl --url https://website --cacert /path/to/servercert.cer

它工作得很好;授权网站返回。

但是,我尝试了以下 PHP 代码:

$handle = curl_init();
$options = array( 
                  CURLOPT_RETURNTRANSFER => false,
                  CURLOPT_HEADER         => true,
                  CURLOPT_FOLLOWLOCATION => false,
                  CURLOPT_SSL_VERIFYHOST => '0',
                  CURLOPT_SSL_VERIFYPEER => '1',
                  CURLOPT_CAINFO         => '/path/to/servercert.cer',
                  CURLOPT_USERAGENT      => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)',
                  CURLOPT_VERBOSE        => true,
                  CURLOPT_URL            => 'https://website'
           );

curl_setopt_array($handle, $options);
curl_exec($handle);
if (curl_errno($handle)) 
  echo 'Error: ' . curl_error($handle);

curl_close($handle);

我原以为代码本质上类似于 shell 命令,但我却收到以下错误消息:

错误:设置证书验证位置时出错:CAfile: /path/to/servercert.cer CApath: none

我已经阅读了我能找到的所有文献(特别是在 php.net 和 curl.haxx 上),但似乎找不到任何可以解决这个问题的东西。有什么建议吗?

我试过chmod 777 servercert.cer 没有成功。但是,在命令行而不是浏览器通过php test.php 使用上述代码执行PHP 脚本时,它可以完美运行。任何解释为什么它在浏览器中不起作用?

【问题讨论】:

PHP 是否确实有权读取该文件?尝试从命令行运行脚本:php my.php 奇怪!我按照你说的测试了,效果很好!为什么它可以从命令行运行,而不是浏览器? serverfault.com/questions/121768/… php运行在什么环境下? 我的回答 [这里][1] 可能会有所帮助 [1]:***.com/a/13564776/324846 【参考方案1】:

因为事情是通过命令行而不是通过使用 curl 的 php 来工作的,所以我会追究 curl 的问题。

根据此 URL,http://curl.haxx.se/docs/sslcerts.html,这是您在上面引用的 SO 帖子中的引用 (reading SSL page with CURL (php))...

“直到 7.18.0,curl 捆绑了一个严重过时的 ca 捆绑文件,该文件是 默认安装。这些天来,curl 档案中没有 ca 证书 全部。你需要把它们带到别处。例如,请参见下文。

如果远程服务器使用自签名证书,如果您没有安装 CA cert bundle,如果服务器使用的证书不是由 CA 签名的 包含在您使用的捆绑包中,或者如果远程主机是冒名顶替者 冒充您最喜欢的站点,并且您想从该站点传输文件 服务器,请执行以下操作之一:"

然后列出您可以尝试的一些步骤。

由于您的 7.16.3 版本的 curl 早于 7.18.0,如果您还没有,我建议您更新您的 curl 和 openssl 组件,然后完成上面引用的列表。

【讨论】:

【参考方案2】:

问了 6 年后,我在共享主机上遇到了同样的问题,显然没有令人满意的答案。我为自己找到了一个解决方案,希望对大家有用。

你可以试试这个配置:

curl_setopt($config,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($config,CURLOPT_SSL_VERIFYPEER,1);
curl_setopt($config,CURLOPT_CAINFO,'ca-bundle.crt');
curl_setopt($config,CURLOPT_CAPATH,'ca-bundle.crt');

我在@Magsol 遇到了同样的错误:Error: error setting certificate verify locations: CAfile: /path/to/servercert.cer CApath: none;所以我添加了第 4 行来设置 CAPath。

这是我的工作。但请注意,CA 文件必须放在可访问的目录中(使用 chmod 755 或 777),如果 CA 文件与 PHP 文件位于同一目录中会更好。

【讨论】:

这行得通,仅当我将路径设置为绝对路径时 ...如果您在与调用 PHP 文件相同的目录中有 ca-bundle.crt,则意味着该路径将其实是__DIR__.'/ca-bundle.crt' omg @jave.web - 在搜索为什么我的查询在从 Windows 服务器移动到 linux 服务器后一小时失败后,这是导致它工作的唯一原因。 Linux 就是找不到我的cacert.pem 文件。谢谢!!!!!!!!!!!!!!!【参考方案3】:

详细说明和总结:

如果你有一个使用 PHP curl 的 PHP 文件并将系统的 ca 证书放在同一目录中,下面的代码将为你提供一个快速启动

    $url = "https://myserver.mydomain.local/get_somedata.php";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);

//These next lines are for the magic "good cert confirmation"
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_VERBOSE, true);

//for local domains:
//you need to get the pem cert file for the root ca or intermediate CA that you signed all the domain certificates with so that PHP curl can use it...sorry batteries not included
//place the pem or crt ca certificate file in the same directory as the php file for this code to work
    curl_setopt($ch, CURLOPT_CAINFO, __DIR__.'/cafile.pem');
    curl_setopt($ch, CURLOPT_CAPATH, __DIR__.'/cafile.pem');

//DEBUG: remove slashes on the next line to prove "SSL verify" is the cause       
//curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

//Error handling and return result
    $data = curl_exec($ch);
    if ($data === false) 
        $result = curl_error($ch);
     else 
        $result = $data;
    

// Close handle
    curl_close($ch);
    return $result;

【讨论】:

哎呀,如果最后的语句引起了双重调用......我的错,这样调整 $data = curl_exec($ch); if ($data === false) $result = curl_error($ch); 其他 $result = $data; 【参考方案4】:

现在这个问题已经很老了,但可能对目前正在寻找答案的一些用户有用。

我对带有 SSL 的 API 有类似的问题,CURL 有问题(不是浏览器)我的问题是我只放了证书而不是证书链/捆绑包。然后我把它和事情开始工作。所以这对于避免问题很重要。

希望这对某人有用。

【讨论】:

【参考方案5】:

如果它适合你,你可以试试这个:

curl_setopt($ch, CURLOPT_URL, "https://test.example.com/v1/authenticate.json?api_key=123456");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_CAINFO,'cert.embedapp.20191004.pem');
curl_setopt($ch,CURLOPT_CAPATH,'./cert.embedapp.20191004.pem');

评论这些行并添加:

//curl_setopt($ch,CURLOPT_CAINFO,'cert.embedapp.20191004.pem');
//curl_setopt($ch,CURLOPT_CAPATH,'./cert.embedapp.20191004.pem');
curl_setopt($ch, CURLOPT_SSLCERT,'cert.embedapp.20191004.pem');

【讨论】:

以上是关于使用带有 SSL 证书的 PHP cURL 时出错的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PHP 中使用 CURL 获取 SSL 证书信息?

如何禁用 cURL SSL 证书验证 [重复]

XAMPP 配置 cURL 错误 60:SSL 证书

“cURL 错误 77:设置证书验证位置时出错”,原因不明

WORDPRESS : cURL 错误 60: SSL 证书

php curl 忽略ssl 不是否等于ssl没有用