Python Urllib2 SSL 错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27804710/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python Urllib2 SSL error
提问by abjennings
Python 2.7.9 is now much more strict about SSL certificate verification. Awesome!
Python 2.7.9 现在对 SSL 证书验证更加严格。惊人的!
I'm not surprised that programs that were working before are now getting CERTIFICATE_VERIFY_FAILED errors. But I can't seem to get them working (without disabling certificate verification entirely).
以前运行的程序现在出现 CERTIFICATE_VERIFY_FAILED 错误,我并不感到惊讶。但我似乎无法让它们工作(不完全禁用证书验证)。
One program was using urllib2 to connect to Amazon S3 over https.
一个程序使用 urllib2 通过 https 连接到 Amazon S3。
I download the root CA certificate into a file called "verisign.pem" and try this:
我将根 CA 证书下载到名为“verisign.pem”的文件中并尝试以下操作:
import urllib2, ssl
context = ssl.create_default_context()
context.load_verify_locations(cafile = "./verisign.pem")
print context.get_ca_certs()
urllib2.urlopen("https://bucket.s3.amazonaws.com/", context=context)
and I still get CERTIFICATE_VERIFY_FAILED errors, even though the root CA is printed out correctly in line 4.
而且我仍然收到 CERTIFICATE_VERIFY_FAILED 错误,即使根 CA 在第 4 行中正确打印出来。
openssl can connect to this server fine. In fact, here is the command I used to get the CA cert:
openssl 可以很好地连接到这个服务器。事实上,这是我用来获取CA证书的命令:
openssl s_client -showcerts -connect bucket.s3.amazonaws.com:443 < /dev/null
I took the last cert in the chain and put it in a PEM file, which openssl reads fine. It's a Verisign certificate with:
我获取了链中的最后一个证书并将其放入 PEM 文件中,openssl 读取正常。这是一个 Verisign 证书,具有:
Serial number: 35:97:31:87:f3:87:3a:07:32:7e:ce:58:0c:9b:7e:da
Subject key identifier: 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33
SHA1 fingerprint: F4:A8:0A:0C:D1:E6:CF:19:0B:8C:BC:6F:BC:99:17:11:D4:82:C9:D0
Any ideas how to get this working with validation enabled?
任何想法如何在启用验证的情况下使其工作?
采纳答案by Steffen Ullrich
To summarize the comments about the cause of the problem and explain the real problem in more detail:
总结一下关于问题原因的评论并更详细地解释真正的问题:
If you check the trust chain for the OpenSSL client you get the following:
如果您检查 OpenSSL 客户端的信任链,您会得到以下信息:
[0] 54:7D:B3:AC:BF:... /CN=*.s3.amazonaws.com
[1] 5D:EB:8F:33:9E:... /CN=VeriSign Class 3 Secure Server CA - G3
[2] F4:A8:0A:0C:D1:... /CN=VeriSign Class 3 Public Primary Certification Authority - G5
[OT] A1:DB:63:93:91:... /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
The first certificate [0] is the leaf certificate sent by the server. The following certifcates [1] and [2] are chain certificates sent by the server. The last certificate [OT] is the trusted root certificate, which is not sent by the server but is in the local storage of trusted CA. Each certificate in the chain is signed by the next one and the last certificate [OT] is trusted, so the trust chain is complete.
第一个证书[0]是服务器发送的叶证书。以下证书 [1] 和 [2] 是服务器发送的链式证书。最后一个证书[OT]是可信根证书,它不是由服务器发送的,而是在可信CA的本地存储中。链中的每个证书都由下一个签名,最后一个证书 [OT] 是可信的,因此信任链是完整的。
If you check the trust chain instead by a browser (e.g. Google Chrome using the NSS library) you get the following chain:
如果您通过浏览器(例如使用 NSS 库的 Google Chrome)检查信任链,您将获得以下链:
[0] 54:7D:B3:AC:BF:... /CN=*.s3.amazonaws.com
[1] 5D:EB:8F:33:9E:... /CN=VeriSign Class 3 Secure Server CA - G3
[NT] 4E:B6:D5:78:49:... /CN=VeriSign Class 3 Public Primary Certification Authority - G5
Here [0] and [1] are again sent by the server, but [NT] is the trusted root certificate. While this looks from the subject exactly like the chain certificate [2] the fingerprint says that the certificates are different. If you would take a closer looks at the certificates [2] and [NT] you would see, that the public key inside the certificate is the same and thus both [2] and [NT] can be used to verify the signature for [1] and thus can be used to build the trust chain.
这里 [0] 和 [1] 又是服务器发送的,但 [NT] 是受信任的根证书。虽然这从主题看起来与链式证书 [2] 完全一样,但指纹表明证书是不同的。如果您仔细查看证书 [2] 和 [NT],您会发现证书中的公钥是相同的,因此 [2] 和 [NT] 都可用于验证 [ 1],因此可用于构建信任链。
This means, that while the server sends the same certificate chain in all cases there are multiple ways to verify the chain up to a trusted root certificate. How this is done depends on the SSL library and on the known trusted root certificates:
这意味着,虽然服务器在所有情况下都发送相同的证书链,但有多种方法可以验证该链直至可信根证书。这是如何完成的取决于 SSL 库和已知的受信任根证书:
[0] (*.s3.amazonaws.com)
|
[1] (Verisign G3) --------------------------\
| |
/------------------ [2] (Verisign G5 F4:A8:0A:0C:D1...) |
| |
| certificates sent by server |
.....|...............................................................|................
| locally trusted root certificates |
| |
[OT] Public Primary Certification Authority [NT] Verisign G5 4E:B6:D5:78:49
OpenSSL library Google Chrome (NSS library)
But the question remains, why your verification was unsuccessful. What you did was to take the trusted root certificate used by the browser (Verisign G5 4E:B6:D5:78:49) together with OpenSSL. But the verification in browser (NSS) and OpenSSL work slightly different:
但问题仍然存在,为什么您的验证不成功。您所做的是将浏览器使用的受信任根证书 (Verisign G5 4E:B6:D5:78:49) 与 OpenSSL 一起使用。但是浏览器 (NSS) 和 OpenSSL 中的验证工作略有不同:
- NSS: build trust chain from certificates send by the server. Stop building the chain when we got a certificate signed by any of the locally trusted root certificates.
- OpenSSL_ build trust chain from the certificates sent by the server. After this is done check if we have a trusted root certificate signing the latest certificate in the chain.
- NSS:从服务器发送的证书构建信任链。当我们获得由任何本地受信任的根证书签署的证书时,停止构建链。
- OpenSSL_ 从服务器发送的证书构建信任链。完成此操作后,检查我们是否有一个受信任的根证书签署链中的最新证书。
Because of this subtle difference OpenSSL is not able to verify the chain [0],[1],[2] against root certificate [NT], because this certificate does not sign the latest element in chain [2] but instead [1]. If the server would instead only sent a chain of [0],[1] then the verification would succeed.
由于这种细微的差异,OpenSSL 无法根据根证书 [NT] 验证链 [0],[1],[2],因为该证书没有签署链 [2] 中的最新元素,而是 [1] . 如果服务器仅发送 [0],[1] 的链,则验证将成功。
This is a long known bugand there exist patchesand hopefully the issue if finally addressed in OpenSSL 1.0.2 with the introduction of the X509_V_FLAG_TRUSTED_FIRST
option.
这是一个长期已知的错误,并且存在补丁,希望通过引入该X509_V_FLAG_TRUSTED_FIRST
选项最终在 OpenSSL 1.0.2 中解决该问题。