curl: (60) SSL证书问题:无法获取本地颁发者证书

486
root@sclrdev:/home/sclr/certs/FreshCerts# curl --ftp-ssl --verbose ftp://{abc}/ -u trup:trup --cacert /etc/ssl/certs/ca-certificates.crt
* About to connect() to {abc} port 21 (#0)
*   Trying {abc}...
* Connected to {abc} ({abc}) port 21 (#0)
< 220-Cerberus FTP Server - Home Edition
< 220-This is the UNLICENSED Home Edition and may be used for home, personal use only
< 220-Welcome to Cerberus FTP Server
< 220 Created by Cerberus, LLC
> AUTH SSL
< 234 Authentication method accepted
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.

我曾经遇到过类似的问题。这个链接对我有用:https://dev59.com/NmAg5IYBdhLWcg3w9e_m#29649024 - Sagruob
2
在我的情况下,https://superuser.com/a/719047/137881 有所帮助。 - Abdull
请查看以下链接以获取解决方案:https://dev59.com/WV4b5IYBdhLWcg3wojFg#61177063 - pankaj
如果您是在组织机构而不是个人电脑上工作,可能会处于代理互联网连接中。如果任何可能的解决方案都不起作用,请请求静态IP。 - Deepak Thakur
显示剩余2条评论
37个回答

353

关于“SSL证书问题:无法获取本地颁发者证书”的错误。重要的是要注意,这适用于发送CURL请求的系统,而不是接收请求的服务器。

  1. https://curl.se/ca/cacert.pem下载最新的cacert.pem文件。

  2. 在curl命令中添加“--cacert /path/to/cacert.pem”选项,告诉curl本地证书颁发机构文件的位置。

  3. (或) 创建或将以下行添加到“.curlrc”文件中: cacert = /path/to/cacert.pem 有关curl查找此文件的信息,请参见“man curl”,有关“-K、--config <file>”部分的信息。

  4. (如果使用php) 添加以下行到php.ini:(如果这是共享托管,并且您无法访问php.ini,则可以将其添加到public_html中的.user.ini中)。

curl.cainfo="/path/to/downloaded/cacert.pem"

请确保将路径括在双引号内!!!

  1. (也许对于php) 默认情况下,FastCGI进程每300秒解析一次新文件(如果需要,您可以通过像https://ss88.uk/blog/fast-cgi-and-user-ini-files-the-new-htaccess/建议的添加一些文件来更改频率)。

6
实际上,我挣扎了一个小时,因为我没有在引号内写路径。所以请注意这里的内容:curl.cainfo="/path/to/downloaded/cacert.pem" // 不要忘记用引号括起来 - Himanshu Upadhyay
50
问题中没有提到PHP,为什么回答中有相关引用?如果问题已经被编辑过了,那么能否编辑回答以反映现在使用的命令行? - Adam
21
虽然问题没有提到PHP,但在谷歌搜索中,这篇文章是关于PHP生成的特定错误信息的排名第一。因此,虽然它可能并没有直接回答提问者的问题,但它似乎对社区仍然有用。 - rinogo
10
这个答案对我来说是误导性的,因为它是一个与PHP相关的解决方案。 - Wasif Khan
2
谢谢您提供的提示:“适用于发送CURL请求的系统”。这对我非常有帮助。 - leole
显示剩余13条评论

347

由于cURL无法验证服务器提供的证书,因此它未能成功。

以下有两种方法可以解决这个问题:

  1. 使用带有-k选项的cURL。该选项允许curl进行不安全的连接,即cURL不验证证书。

  2. 将根CA(签署服务器证书的CA)添加到/etc/ssl/certs/ca-certificates.crt中。

你应该选择第二种方法,因为只有这种方法可以确保你连接到了安全的FTP服务器。


1
我将我的rootCA.pem文件添加到以下位置:- root@sclrdev:/home/certs/FreshCerts# ll /etc/ssl/certs/rootCA.pem -rwxrwxrwx 1 root root 1302 Jul 8 00:09 /etc/ssl/certs/rootCA.pem*我还使用我的rootCA.pem验证了ServerCertificate.pem文件:- root@sclrdev:/home/certs/FreshCerts# openssl verify -CAfile rootCA.pem ../ServerCertificate.pem ServerCertificate.pem: OK并且在ca-certificates.crt中也包含了rootCA.pem的内容。 root@sclrdev:/home/sclr/subhendu/certs/FreshCerts# ll /etc/ssl/certs/ca-certificates.crt -rw-r--r-- 1 root root 247945 Jul 8 00:10 /etc/ssl/certs/ca-certificates.crt - user3812540
我无法弄清楚我的错误在哪里。在WireShark跟踪中,我收到以下错误:- 客户端Hello 服务器Hello,证书,服务器Hello完成 警报(级别:致命,描述:未知CA(48))您能否指导并帮助我解决这个问题? - user3812540
OpenSSL的工作方式是在验证过程中尝试完成证书链。你的服务器证书是否由中间CA签名而不是根CA签名?例如。 - Yuvika
我能想到的另一件事是,确保使用数据包捕获测试服务器证书时,所使用的证书与服务器提供的证书相同。您还可以通过使用以下命令查看证书:openssl s_client -connect <server>:443 -showcerts - Yuvika
1

我遇到了一些错误: root@sclrdev:~# openssl s_client -connect <server_ip>:21 -showcerts CONNECTED(00000003) 3074050248:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:766:

没有可用的对等证书

未发送客户端证书CA名称

SSL握手已读取7个字节并写入225个字节

新的,(无),密码是(无) 不支持安全重协商 压缩:无 扩展:无

我不确定这到底意味着什么?
- user3812540
显示剩余9条评论

105

我通过在cURL脚本中添加一行代码解决了这个问题:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

警告:这使得请求绝对不安全(请参见@YSU的答案)!


75
这可能有助于规避问题,但完全忽略了HTTPS和认证系统的概念。 - Stephan Richter
3
可以用!如果您不关心证书,这是一个不错的快速绕过方法。 - Gilly
6
这使它完全不安全。 - Moox
1
尽管相同的代码在暂存服务器上运行良好,但我在本地服务器上遇到了这个问题。对我来说是可以接受的,因为它只是在本地出现了问题。谢谢。 - sabin
5
请添加此检查以确保仅在本地服务器上使用它:if( stristr("127.0.0.1",$_SERVER["SERVER_NAME"] ) || stristr("localhost",$_SERVER["SERVER_NAME"] )) curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - Hussain
显示剩余4条评论

38

对我来说,简单安装证书就解决了问题:

sudo apt-get install ca-certificates

4
例如,有些小的Docker容器可能没有安装这个软件包,当整个软件包不存在时,解决其他任何问题都是无意义的。 - Anton Krug

32
在我的情况下,问题出在我试图使用cURL消费的服务上安装证书上。我未能将中间证书和根证书与我的域名证书捆绑/合并在一起。一开始并不明显这是问题所在,因为Chrome可以解决它,并接受证书,尽管遗漏了中间和根证书。在捆绑证书后,一切都按预期工作了。我像这样捆绑了证书:
$ cat intermediate.crt >> domain.crt

对所有中间证书和根证书都要重复此操作。


2
我遇到了类似的问题,只是我的Apache SSLCertificateChainFile没有设置正确的证书。 - Wayne Piekarski
3
注意,如果你这样做,并且添加的证书没有结尾的换行符,那么你的合集文件中将会出现像-----END CERTIFICATE----------BEGIN CERTIFICATE-----这样的行,然后你会收到类似于curl: (77) error setting certificate verify locations这样晦涩难懂的错误提示。 - Marty Neal
2
我正在使用letsencrypt证书,但只部署了证书和私钥到服务器。我的电脑上的Chrome和curl没有出现问题,但是我正在构建的一个nodejs应用程序却无法接受该证书。将fullchain部署到服务器上解决了这个问题!感谢您指出正确的方向! - Paulo Santos
在我的情况下(来自卡莫多的证书),他们将中间证书作为my-domain.ca-bundle发送。我必须将其附加到my-domain.crt上。谢谢! - Jon Hulka
它对我有效。谢谢。我从Digitcert获取了域证书、中间证书和根证书,但在nginx配置中只引用了域证书。 - focus zheng

23

在安装 Git Extensions v3.48 后遇到了这个问题。尝试重新安装 mysysgit,但仍然出现相同的问题。最后,不得不禁用(请考虑安全影响!)Git SSL 验证:

git config --global http.sslVerify false

但是如果您有域名证书,最好将其添加到(Win7)中。

C:\Program Files (x86)\Git\bin\curl-ca-bundle.crt

30
可以工作,但感觉像是掩盖症状,而非治愈疾病。 - MonoThreaded
7
禁用SSL验证非常危险。 - Jonas Lejon
1
你可以不使用 --global,只在出现问题的仓库中禁用SSL。请参考https://groups.google.com/forum/#!topic/git-for-windows/mlqn5J4OLlw以了解当前必要的crt文件的讨论。 - koppor

19

很可能是服务器缺少证书。

根证书->中间证书->服务器证书

服务器应至少发送服务器证书和中间证书。

使用 openssl s_client -showcerts -starttls ftp -crlf -connect abc:21 调试问题。

如果只返回一个证书(自签名或已签发),则您必须选择以下操作之一:

  1. 修复服务器
  2. 信任该证书并将其添加到您的 CA 证书存储区(不是最好的方法)
  3. 禁用信任,例如 curl -k(非常糟糕的想法)

如果服务器返回了多个证书,但不包括自签名(根)证书:

  1. 为此链中的 CA(根)证书安装在您的 CA 存储库中,例如谷歌搜索发行者。(仅当您信任该 CA 时)
  2. 修复服务器以发送 CA 作为链的一部分
  3. 信任链中的证书
  4. 禁用信任

如果服务器返回了一个根 CA 证书,则它不在您的 CA 存储库中,您的选项是:

  1. 添加(信任)它
  2. 禁用信任

我忽略了已过期/吊销的证书,因为没有相关的信息。但您可以使用 openssl x509 -text 检查证书。

由于您正在连接到家用版 (https://www.cerberusftp.com/support/help/installing-a-certificate/) ftp 服务器,我认为它是自签名的。

请发布更多详细信息,例如从 openssl 输出的内容。


我不确定是否错了,但根据openssl的手册,-showcerts标志应仅显示已发送的远程证书。因此,如果您使用该测试,似乎即使本地和正确的整个链路都存在,openssl也可能输出错误(因为您只查看已发送的证书链,该链可能不完整)。 我建议使用curl -vvv www.google.ch:443进行测试,以测试本地存储是否已经正确,并使用openssl -showcerts查看已发送的证书链。到目前为止,我没有找到任何其他解决方案来区分和检查本地和远程。 - Dorian Gaensslen
你也可以使用testssl.h来检查是否存在fullchain证书。 - tianjianchn

15
我们最近遇到了这个错误。原来与根证书未正确安装在CA存储目录有关。我正在使用curl命令直接指定CA目录。 curl --cacert /etc/test/server.pem --capath /etc/test ... 该命令每次都失败,显示curl: (60) SSL certificate problem: unable to get local issuer certificate. 使用strace curl ...后,确定curl正在查找以60ff2731.0命名的根证书文件,这是基于openssl散列命名约定得出的结果。所以我找到了这个有效导入根证书的命令:

ln -s rootcert.pem `openssl x509 -hash -noout -in rootcert.pem`.0

它创建了一个软链接

60ff2731.0 -> rootcert.pem

在内部,curl读取server.pem证书,确定根证书文件的名称(rootcert.pem),将其转换为其哈希名称,然后进行OS文件查找,但找不到它。
因此,结论是,在curl错误模糊时使用strace会非常有帮助,然后请确保使用openssl命名约定正确安装根证书。

3
哎呀,这确实有帮助。稍微详细解释一下是什么帮了我:a) 运行 strace curl... b) 查找出现 failed stat() 和 something-hex.0 的地方 c) 搜索 something-hex,找到相应的证书 d) 将找到的证书放入 /usr/local/share/ca-certificates/(使用 *.crt 扩展名,因为 *.pem 不起作用) e) 运行 update-ca-certificates。然后 Bingo!必要的符号链接在 /usr/lib/ssl/certs/ 中被自动创建了。 - No-Bugs Hare
这里有一个很好的解释:https://dev59.com/z2kw5IYBdhLWcg3wdKQv - austinheiman
这里有一个很好的解释:https://stackoverflow.com/questions/9879688/difference-between-cacert-and-capath-in-curl - undefined
我一直在使用MariaDB的双向SSL遇到同样的问题。显然,尽管它似乎没有记录,但MariaDB(以及可能是MySQL)遵循与curl相同的规则。如果您通过ssl_capath(选项文件)或--ssl-capath(客户端命令行参数)指定ca目录,则CA证书文件名必须遵循openssl哈希命名约定。您7年前的答案救了我。 - undefined

12

只更新证书列表可能就足够了。

sudo update-ca-certificates -f

update-ca-certificates 是一个更新目录 /etc/ssl/certs 中 SSL 证书并生成 ca-certificates.crt 单一文件列表的程序。


3
完成了所有运行操作,但是curl无法工作。错误依旧存在。 - AGamePlayer
1
我执行了命令,但没有帮助,我简直不敢相信我必须做以上所有的事情。然后你的回答是...感谢“-f”标志。 - Alex Shtromberg
1
你救了我的一天。 - Irakli

11
  1. 下载 https://curl.haxx.se/ca/cacert.pem

  2. 下载后,将该文件移动到您的WAMP服务器中。

    例如:D:\wamp\bin\php\

  3. 然后在php.ini文件末尾添加以下行:

curl.cainfo="D:\wamp\bin\php\cacert.pem"

  1. 现在重新启动您的WAMP服务器。

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