29

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

在这种情况下,curl_setopt($handle, CURLOPT_VERIFYPEER, 0)不幸的是不是一个选择。证书是身份验证的必需部分,否则我会收到其他类似 SO 帖子中提到的错误。

我用 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:无

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

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

4

5 回答 5

17

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

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

“在 7.18.0 之前,curl 捆绑了一个默认安装的严重过时的 ca 捆绑文件。这些天来,curl 档案根本不包含 ca 证书。您需要在其他地方获取它们。例如,请参见下文。

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

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

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

于 2012-05-02T16:30:48.213 回答
8

经过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 文件位于同一目录中会更好。

于 2015-12-08T09:55:29.000 回答
8

详细说明和总结一下:

如果您有一个使用 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;
于 2017-07-14T17:15:44.820 回答
4

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

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

希望这对某人有用。

于 2015-10-01T13:14:25.163 回答
1

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

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');
于 2019-10-14T12:58:59.107 回答