配置 cURL 以支持 SSL

6
我们的网站最近从http转移到了https。我们的客户调用REST API,但现在无法正常工作:
SSL之前的cURL(可用):
$ch = curl_init();

curl_setopt($ch,CURLOPT_URL,$api_call_url);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

$result = curl_exec($ch);

curl_close($ch);

SSL后的cURL(不起作用):
$ch = curl_init();

curl_setopt($ch,CURLOPT_URL,$api_call_url);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, "/customers_path_on_their_server/to/our_cacert_they_exported_via_firefox.crt");   //X.509 Certificate

$result = curl_exec($ch);

curl_close($ch);

除了要求客户在其 REST 集成代码中添加 CURLOPT_SSL_VERIFYPEER、CURLOPT_SSL_VERIFYHOST 和 CURLOPT_CAINFO 之外,我需要在我们的服务器上设置什么吗?

我对 HTTPS 真的是个新手,不知道我需要搜索什么术语,已经搜索了几个小时的 cURL SSL ……

顺便说一下,如果这些信息有用的话,我们的站点使用亚马逊 EC2 托管……

这是返回的 cURL 错误:

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

cURL版本:7.21.6

SSL版本:OpenSSL/1.0.0e


1
https://dev59.com/BWw15IYBdhLWcg3wxuvL - nkamm
@nkamm,还是不行。我已经检查了从Firefox导出的.crt文件,它存储在我们客户的服务器上,和我们服务器上的.crt文件是否相同。它们是一样的。我们服务器上的.crt文件位于/etc/apache2/ssl/our_site.crt。你认为我应该将它移动到其他地方吗...我已经花了5个多小时来解决这个问题了....天哪... - Woppi
还要请他们使用选择中的第二个选项(在Firefox中)导出证书 http://i.stack.imgur.com/kZpCQ.png - nkamm
@nkamm 是的,那就是我所做的。我有另一个服务器可以作为客户端,并保存从Firefox导出的.crt文件。我实际上将其与我们的REST API服务器中位于etc/apache2/ssl目录下的.crt文件进行了比较,它们是相同的。我还将.crt文件的权限设置为777。 - Woppi
只需设置 CURLOPT_SSL_VERIFYPEER, 0CURLOPT_SSL_VERIFYHOST, 0 即可解决此错误,无需添加证书。(如果您信任源,则无需进行验证)。 - Cyborg
2个回答

8
不要像其他人建议的那样关闭对等和主机验证。这是一个不安全的解决方案,真正的问题并没有得到解决。这些功能之所以存在,是为了让你能够信任通过第三方连接到的系统是否符合你的期望。
首先,查找你的操作系统是否包含证书目录。证书授权通常会被包含在其中。例如,在Ubuntu上,它通常位于目录/etc/ssl/certs中,而基于Red Hat的发行版将其包含在/etc/pki/tls/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');

1

为了扩展Matt的回答,两个cURL设置CURLOPT_CAPATHCURLOPT_CAINFO执行不同的功能并且行为差异很大。

CURLOPT_CAINFO指的是单个文件,可以是证书束或者更少见的单个证书。该值可以(而且应该)在php.ini中永久设置,使用curl.cainfo directive

证书束只是一些串联的证书,表示哪些CA发行将被信任。如果您没有一个,您的操作系统可能提供一个可安装的软件包。在RHEL上,可以使用yum install ca-certificates完成此操作,而Debian/Ubuntu则使用apt install ca-certificates。如果您的操作系统没有提供软件包,cURL的制造商提供一个下载链接以获取由Mozilla创建的证书束。

CURLOPT_CAPATH 指的是一个包含个人证书的目录。如果您请求的主机名与证书的通用名称匹配,cURL 可以使用此目录中的证书。但是,重要的是要注意,这不会自动发生。如果您设置了 CA 路径,则必须确保该目录中要使用的任何证书都具有适当命名的符号链接(请参阅下文)。


所以,综合起来,我们得到了以下典型的设置。
将cURL永久指向系统包,可以在php.ini中使用以下类似代码:
[curl]
; for RHEL
curl.cainfo=/etc/pki/tls/certs/ca-bundle.crt
; for Debian/Ubuntu
curl.cainfo=/etc/ssl/certs/ca-certificates.crt

这是连接到由可信CA颁发的公共服务器所需做的全部内容,即几乎互联网上的所有内容。如果这就是你需要的,那么你已经完成了。
对于其余情况,例如连接到使用由公司CA颁发的证书的设备,请确保将相关证书复制到目录中并正确设置符号链接名称:
#!/bin/bash
cd /path/to/my/certs/
for c in *.crt; do ln -s "$c" "$(openssl x509 -hash -noout -in "$c").0"; done

然后在您的代码中使用此cURL选项来设置CA路径:

<?php
$ch = curl_init("https://some.device.internal");
curl_setopt($ch, CURLOPT_CAPATH, "/path/to/my/certs/");
$result = curl_init($ch);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接