值得再多讲一些关于这里发生的事情的“实践”光,补充@Steffen Ullrich在这里和其他地方的答案:
注:
- 我将使用另一个网站而不是OP,因为OP的网站目前没有问题。
- 我使用Ubunto运行以下命令(
curl
和openssl
)。我尝试在我的Windows 10上运行curl
,但输出不同且没有帮助。
通过使用以下curl
命令可以“复制”OP遇到的错误:
curl -vvI https://www.vimmi.net
输出结果为(请注意最后一行):
* TCP_NODELAY set
* Connected to www.vimmi.net (82.80.192.7) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* stopped the pause stream!
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
现在让我们使用
--insecure
标志运行它,这将显示有问题的证书:
curl --insecure -vvI https://www.vimmi.net
输出(注意最后两行):
* Rebuilt URL to: https://www.vimmi.net/
* Trying 82.80.192.7...
* TCP_NODELAY set
* Connected to www.vimmi.net (82.80.192.7) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* [...]
* Server certificate:
* subject: OU=Domain Control Validated; CN=vimmi.net
* start date: Aug 5 15:43:45 2019 GMT
* expire date: Oct 4 16:16:12 2020 GMT
* issuer: C=US; ST=Arizona; L=Scottsdale; O=GoDaddy.com, Inc.; OU=http://certs.godaddy.com/repository/; CN=Go Daddy Secure Certificate Authority - G2
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
同样的结果可以使用openssl
来查看,值得一提的是,它被Python内部使用:
echo | openssl s_client -connect vimmi.net:443
输出:
CONNECTED(00000005)
depth=0 OU = Domain Control Validated, CN = vimmi.net
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = vimmi.net
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:OU = Domain Control Validated, CN = vimmi.net
i:C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certs.godaddy.com/repository/, CN = Go Daddy Secure Certificate Authority - G2
---
Server certificate
-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----
[...]
---
DONE
那么为什么curl和openssl都无法验证Go Daddy为该网站颁发的证书呢?
嗯,"验证证书"(使用openssl的错误消息术语)意味着验证证书包含受信任源签名(换句话说:证书是由受信任源签名的),从而验证vimmi.net
的身份(这里的“身份”严格意义上是指“证书中包含的公钥属于证书中注明的个人、组织、服务器或其他实体”)。
如果我们可以建立其"信任链",则源是"受信任的", 具有以下属性:
- 每个证书的颁发者(除了最后一个)与列表中下一个证书的主题相匹配
- 每个证书(除了最后一个)都由对应于链中下一个证书的密钥签名(即,可以使用包含在以下证书中的公钥验证一个证书的签名)
- 列表中的最后一个证书是信任锚点:您信任它,因为它是通过某些可信赖的程序交付给您的证书
在我们的情况下,颁发者是“Go Daddy Secure Certificate Authority - G2”。也就是说,名为“Go Daddy Secure Certificate Authority - G2”的实体签署了该证书,因此它应该是一个受信任的源。
要建立这个实体的信任度,我们有两个选择:
假设“Go Daddy Secure Certificate Authority - G2”是一个“信任锚点”(见上面的第3个清单)。实际上,
curl
和
openssl
试图根据这个假设进行操作:它们在默认路径(称为CA路径)上搜索该实体的证书,这些路径分别是:
curl
的路径是/etc/ssl/certs
。
openssl
的路径是/use/lib/ssl
(运行openssl version -a
查看)。
但是没有找到那个证书,留下了我们的第二个选择:
- 按照上面列出的步骤1和2进行操作;为了实现这一点,我们需要为该实体颁发证书。
可以通过从其来源下载或使用浏览器来实现。
- 例如,使用Chrome浏览器打开
vimmi.net
,单击挂锁 > “证书” > “认证路径”选项卡,选择实体 > “查看证书”,然后在打开的窗口中转到“详细信息”选项卡 > “复制到文件” > 基于64位编码 > 保存文件)
太好了!现在我们有了那个证书(它可以是任何文件格式:cer
, pem
等;您甚至可以将其保存为txt
文件),让我们告诉curl
如何使用它:
curl --cacert test.cer https://vimmi.net
回到Python
一旦我们拥有:
- "Go Daddy Secure Certificate Authority - G2"证书
- "Go Daddy Root Certificate Authority - G2"证书(上面没有提到,但可以通过类似的方式实现)。
我们需要将它们的内容复制到一个单独的文件中,让我们称之为combined.cer
,并将其放置在当前目录中。然后,只需要执行以下操作:
import requests
res = requests.get("https://vimmi.net", verify="./combined.cer")
print (res.status_code)
- 顺便提一下,“Go Daddy 根证书颁发机构 - G2”已被浏览器和各种工具列为可信任的机构;这就是为什么我们不需要为
curl
指定它。
更多阅读:
https://www.thenewboston.com/tops.php?type=text&period=this-month&page=1
时,出现了“文件未找到”的消息。您能验证页面是否存在吗? - NuclearPeonhttps://www.thenewboston.com/forum/category.php?id=15&orderby=recent&page=
这个链接,应该可以带你到网站的 Python 部分,但是我用它仍然遇到了完全相同的错误。 - Bill Jenkins