简体   繁体   English

Python 3 带有自签名证书的 urllib

[英]Python 3 urllib with self-signed certificates

I'm attempting to download some data from an internal server using Python. Since it's internal, it uses a self-signed certificate.我正在尝试使用 Python 从内部服务器下载一些数据。由于它是内部服务器,因此它使用自签名证书。 (We don't want to pay Verisign for servers that will never appear "in the wild.") The Python 2.6 version of the code worked fine. (我们不想为永远不会出现在“野外”的服务器支付 Verisign 费用。)代码的 Python 2.6 版本运行良好。

response = urllib2.urlopen(URL)
data = csv.reader(response)

I'm now trying to update to Python 3.4 (long story, don't ask.) However, using Python 3's urllib fails:我现在正在尝试更新到 Python 3.4(长话短说,不要问。)但是,使用 Python 3 的 urllib 失败:

response = urllib.request.urlopen(URL)

It throws a CERTIFICATE_VERIFY_FAILED error.它会抛出 CERTIFICATE_VERIFY_FAILED 错误。

urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:600)>

In reading around the web, apparently Python 2.6 urllib2 doesn't bother to verify certificates.在阅读 web 时,显然 Python 2.6 urllib2 不会费心验证证书。 Some versions of urllib allow "verify=False" to be passed to the method signature, but that doesn't appear to work in Python 3.4.某些版本的 urllib 允许将“verify=False”传递给方法签名,但这在 Python 3.4 中似乎不起作用。

Does anyone know how I can get around this?有谁知道我该如何解决这个问题? I'd like to avoid using the Requests package because of corporate security guidelines.由于公司安全准则,我想避免使用请求 package。

Use following for disabling SSL certificate validation for a URL使用以下内容禁用 URL 的 SSL 证书验证

import ssl
myssl = ssl.create_default_context();
myssl.check_hostname=False
myssl.verify_mode=ssl.CERT_NONE
urlopen("URL",context=myssl)

Use following to disable SSL certificate validations for all URLs使用以下内容禁用所有 URL 的 SSL 证书验证

 ssl._create_default_https_context = ssl._create_unverified_context
 urlopen("URL");

urllib.request.urlopen has a context keyword parameter that accepts an SSLContext object. urllib.request.urlopen有一个接受SSLContext对象的上下文关键字参数。 So, passing a SSLContext object with .verify_mode set to ssl.CERT_NONE ie SSLContext.verify_mode = ssl.CERT_NONE should be equal to verify=False因此,传递一个.verify_mode设置为ssl.CERT_NONESSLContext对象,即SSLContext.verify_mode = ssl.CERT_NONE应该等于verify=False

With urllib3 :使用urllib3

import urllib3

urllib3.disable_warnings()

http.request('GET', 'https://example.org')

As this answer still pops out first when I google for 'CERTIFICATE_VERIFY_FAILED error', I would like to provide an Update: Fully turning off SSL verification is not a good practice in general (I'll give a reason below).由于当我用谷歌搜索“CERTIFICATE_VERIFY_FAILED 错误”时这个答案仍然首先弹出,我想提供一个更新:完全关闭 SSL 验证通常不是一个好的做法(我将在下面给出原因)。 It is better to add the self-signed certificate to the locally trusted certificates than to deactivate the verification completely:最好将自签名证书添加到本地受信任的证书中,而不是完全停用验证:

import ssl
# add self_signed cert
myssl = ssl.create_default_context()
myssl.load_verify_locations('my_server_cert.pem')
# send request
response = urllib.request.urlopen("URL",context=myssl)

Why should we care about certificate validation?我们为什么要关心证书验证?

NIST and other cyber-security organizations recommend the zero-trust model . NIST 和其他网络安全组织推荐零信任 model In short, that means: just because your server is only in the local.network, it is not protected.简而言之,这意味着:仅仅因为您的服务器仅在本地网络中,所以它不受保护。 You should take a minimum effort to secure everything in the local.network.您应该尽可能地保护 local.network 中的所有内容。

So if you have a web server with SSL and the security certificates are not validated by the client, any attacker could still impersonate this web server or steal information by starting a man-in-the-middle attack.因此,如果您有一个带有 SSL 的 web 服务器,并且客户端未验证安全证书,任何攻击者仍然可以冒充此 web 服务器或通过发起中间人攻击来窃取信息。

You already have the private SSL certificate, so why not add it on client side and enjoy the full protection of SSL?您已经拥有私有证书 SSL,那么为什么不在客户端添加它并享受 SSL 的全面保护呢?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM