PHP - SSL证书错误:无法获取本地颁发者证书

247

我在Windows 7上使用XAMPP作为服务器,PHP版本为5.6.3。

当我尝试使用Mandrill API时,出现以下错误:

Uncaught exception 'Mandrill_HttpError' with message 'API call to messages/send-template failed: SSL certificate problem: unable to get local issuer certificate'

我已经尝试了StackOverflow上的所有方法,包括在php.ini文件中添加以下内容:

curl.cainfo = "C:\xampp\php\cacert.pem"

当然,从http://curl.haxx.se/docs/caextract.html下载cacert.pem文件到该位置后进行了下载。

但是即便如此,重新启动XAMPP和Apache服务器仍然会出现相同的错误。

我真的不知道还能尝试什么。

有人能建议我还可以尝试什么吗?


请查看我的回答:https://dev59.com/NmAg5IYBdhLWcg3w9e_m#29649024 - Michal
3
请确保您已取消注释该行代码,即删除了起始的 ';'。应该是 curl.cainfo = "C:\xampp\php\cacert.pem" 而不是 ;curl.cainfo = "C:\xampp\php\cacert.pem"。 - Jon Tan
使用HTTPS而不是HTTP会导致这个错误吗? - leonard.javiniar
有人关心安全吗?证书颁发机构在哪里,如何添加一个? - undefined
20个回答

530

终于让它工作了!

  1. 下载证书包

  2. 将它放在某个地方,例如我的情况是在c:\wamp\目录下(如果您使用的是Wamp 64位,则为c:\wamp64\)。

  3. 在Apache中启用mod_sslphp_openssl.dll,并在php.ini中取消注释(通过删除开头的;)。但要注意,我的问题在于我有两个php.ini文件,我需要在这两个文件中都这样做。一个是您从WAMP任务栏图标获取的文件,另一个是在我的情况下位于C:\wamp\bin\php\php5.5.12\

  4. 在两个php.ini文件中添加以下行:

    curl.cainfo="C:/wamp/cacert.pem"
    openssl.cafile="C:/wamp/cacert.pem"
    
  5. 重新启动Wamp服务。


3
在我的情况下,这是c:\xamp\目录和它的Windows 7,这个解决方案非常完美。非常感谢。 - Manu R S
1
最新的证书包可以从原始的curl网站https://curl.haxx.se/docs/caextract.html下载。 - Paul
2
在我的情况下,这行代码开头有一个 ;,花了我几个小时才意识到它是一条注释。所以对于像我这样的新手,需要将 ; 删除。 - otaku
1
@SurajNeupane 不太确定,我曾经花了很多时间才解决这个问题,我使用虚拟机,比如Homestead,所以我不必处理这个问题。这是一个特殊情况。 - Mladen Janjetovic
10
这是关键所在:“但要小心,我的问题在于我有两个php.ini文件,而我需要在它们两个中都进行修改。一个是你从WAMP任务栏图标中获取的,另一个则是(以我的情况为例)在C:\wamp\bin\php\php5.5.12\中。” - Amr Aly
显示剩余11条评论

180

编辑注:禁用SSL验证会涉及安全风险。如果没有验证SSL/HTTPS连接的真实性,恶意攻击者可以冒充受信任的终端(如GitHub或其他远程Git主机),您将容易受到中间人攻击

在使用此解决方案之前,请确保您充分了解安全问题。

我在Mandrill.php文件中第65行后遇到了同样的问题,其中写着$this->ch = curl_init();

添加以下两行:

curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0);

这解决了我的问题并且使用本地主机发送了电子邮件,但我建议在正式版本中不要使用它。在您的生产服务器上,该代码应该可以正常工作,而无需此代码。


1
有什么方法可以尝试让我的开发环境在没有绕过的情况下正常工作吗? - Dor Dadush
5
对我而言,只需将 CURLOPT_SSL_VERIFYPEER 设置为 false 就可以了。 - Francisco Corrales Morales
36
虽然从技术角度来看你是正确的,但禁用SSL不是一个好主意。即使在本地主机上,最好像其他答案中提到的那样正确加载证书。 - Spinal
虽然你在技术上是正确的,但禁用SSL是一个坏主意。即使它非常抵制以其他方式工作,也最好失去工作,而不是按照非适当的系统管理员方式做事。@Spinal - user5132647
我对“您的服务器不安全”感到困惑,如果我使用这个片段ping一个外部API,会使我的客户端不安全吗? - Robert Sinclair

48

谢谢 @Mladen Janjetovic,

你的建议在我的Mac电脑上安装了AMPPS后对我起了作用。

复制:http://curl.haxx.se/ca/cacert.pem

到:/Applications/AMPPS/extra/etc/openssl/certs/cacert.pem

并更新了php.ini路径,重新启动了Apache:

[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo="/Applications/AMPPS/extra/etc/openssl/certs/cacert.pem"
openssl.cafile="/Applications/AMPPS/extra/etc/openssl/certs/cacert.pem"

我在Windows的AMPPS安装中应用了相同的设置,它也完美地运行了。

[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo="C:/Ampps/php/extras/ssl/cacert.pem"
openssl.cafile="C:/Ampps/php/extras/ssl/cacert.pem"

对于wamp也是同样的情况。

[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo="C:/wamp/bin/php/php5.6.16/extras/ssl/cacert.pem"
openssl.cafile="C:/wamp/bin/php/php5.6.16/extras/ssl/cacert.pem"

如果您想要使用SAN为本地主机生成新的SSL证书,可以按照此篇文章中的步骤操作,在Centos 7 / Vagrant / Chrome浏览器上对我有效。


18

1
这解决了我整天苦苦挣扎的AWS/Guzzle/cURL问题。谢谢! - voidstate
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - John
@John 但那会禁用SSL验证,这不是你想要做的,所以我不建议这样做。 - Arturo Alvarado
1
对于Windows系统,您需要将文件保存在服务器上(例如C:\ curl \ curl-ca-bundle.crt),然后将以下内容添加到php.ini文件中:[curl] curl.cainfo="C:/curl/curl-ca-bundle.crt"[openssl] openssl.cafile="C:/curl/curl-ca-bundle.crt" - voidstate
它之前一直完美运行(甚至经历了服务器更改),但现在我有些困惑,不太明白这里到底发生了什么。是curl或openssl被更新并且其ca-bundle更改为与mailchimp不兼容的版本了吗? - Sammaye
那些词语不再出现在该网址上,所以我不确定这个答案是否仍然相关,是吗? - Simon East

15

上述步骤对我在Windows 8上没有作用。我不知道它们之间的关联,但以下步骤有效。基本上要修改cacert.pem文件。希望这能帮助到某个人。

  • 从此处下载cacert.pem文件: http://curl.haxx.se/docs/caextract.html
  • 将文件保存在您的PHP安装文件夹中(例如:如果使用xampp,请将其保存在c:\ Installation_Dir \ xampp \ php \ cacert.pem中)。
  • 打开php.ini文件并添加以下行:
  • curl.cainfo = ”C:\ Installation_Dir \ xampp \ php \ cacert.pem” openssl.cafile = ”C:\ Installation_Dir \ xampp \ php \ cacert.pem”
  • 重新启动Apache服务器即可解决问题(根据需要停止和启动服务即可)。

14

Note: 禁用SSL验证会带来安全风险。 在没有对SSL/HTTPS连接的真实性进行验证的情况下,恶意攻击者可以冒充受信任的终端点(如GitHub或其他远程Git主机),这将使您容易受到中间人攻击

在使用此解决方案之前,请确保您完全了解安全问题。

我找到了一种新的解决方案,只需添加两行代码即可调用curl,而无需任何必要的认证。

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

12
尽管这可能有效,但这并不被推荐。基本上你是在说,相信所有证书...如果你忘记并且你的代码带着这个更改进入生产环境,它还会使你的应用程序开放给可能的攻击...下载CA捆绑包并将其添加到PHP中真的不需要花费太多工作量。 - tinonetic
这是关于curl概念的内容,因此每当您使用curl时,请添加上述代码。 - Manish sharma
2
这个解决方案可能导致中间人攻击,不建议使用。 - jerryurenaa

10
如果你无法访问php.ini,在$ch = curl_init();这一行之后添加以下代码对我有用:
$certificate_location = "C:\Program Files (x86)\EasyPHP-Devserver-16.1\ca-bundle.crt"; // modify this line accordingly (may need to be absolute)
curl_setopt($ch, CURLOPT_CAINFO, $certificate_location);
curl_setopt($ch, CURLOPT_CAPATH, $certificate_location);

然后,您只需要下载ca-bundle.crt并将其保存到$certificate_location指定的位置。


6

编辑注:禁用SSL验证会有安全风险。如果没有对SSL/HTTPS连接的真实性进行验证,恶意攻击者可以模拟受信任的端点(如GitHub或其他远程Git主机),您将容易受到中间人攻击的威胁。

务必充分了解安全问题后再使用此方法。

我尝试过这个,它可以工作

打开

vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php

并更改此内容

 $conf[CURLOPT_SSL_VERIFYHOST] = 2;
 $conf[CURLOPT_SSL_VERIFYPEER] = true;

转换为这样

$conf[CURLOPT_SSL_VERIFYHOST] = 0;
$conf[CURLOPT_SSL_VERIFYPEER] = FALSE;

2
如果有比在您的“供应商”目录中编辑文件更愚蠢的事情,那就是不验证TLS主机证书。 - miken32

6

注意:禁用SSL验证会带来安全隐患。如果没有验证SSL / HTTPS连接的真实性,恶意攻击者可以冒充受信任的终端点(如GitHub或其他远程Git主机),您将容易受到中间人攻击的攻击。

确保您充分了解安全问题后再使用此解决方案。

对于服务器部署的上述答案进行详细阐述。

$hostname = gethostname();
if($hostname=="mydevpc")
{
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
}

应该可以在开发环境中使用,而不会在部署时影响服务器。


在不同的环境中运行代码的不同部分听起来并不是一个好的概念 - 它会使调试变得更加困难。 - Nico Haase

1
在Amazon Linux(CentOS / Red Hat等)中,我采取了以下措施来解决此问题。首先复制从http://curl.haxx.se/ca/cacert.pem下载的cacert.pem文件,并将其放入/etc/pki/ca-trust/source/anchors/目录中。然后运行update-ca-trust命令。
下面是来自https://serverfault.com/questions/394815/how-to-update-curl-ca-bundle-on-redhat的一行代码: curl https://curl.se/ca/cacert.pem -o /etc/pki/ca-trust/source/anchors/curl-cacert-updated.pem && update-ca-trust 但是由于curl出现问题,我实际上使用了这个命令来下载cacert.pem文件。 wget --no-check-certificate http://curl.haxx.se/ca/cacert.pem 在运行 update-ca-trust 命令后,您可以重新启动 Apache 的 Web 服务器 service httpd restart 或 Nginx 的 service nginx restart

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