我希望向使用我的自签名证书的URL发出经过验证的请求(使用Python 3.5的urllib)。
这是一个最小的示例:
import ssl
from urllib.request import urlopen
from urllib.error import URLError
# <version 1>
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ssl_ctx.verify_mode = ssl.CERT_REQUIRED
ssl_ctx.load_cert_chain(certfile="/path/to/cert.pem", keyfile="/path/to/cert.key")
# </version 1>
try:
urlopen("https://localhost/", context=ssl_ctx)
except URLError as e:
print(e)
此打印:
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:720)>
ssl_ctx.get_ca_certs()
-> []
ssl_ctx.cert_store_stats()
-> {'x509_ca': 0, 'crl': 0, 'x509': 0}
正如为answer指定的Python 3 urllib with self-signed certificates所指出的,我可以通过以下方法解决此问题:
# <version 2>
ssl_ctx = ssl.create_default_context()
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.CERT_NONE
# </version 2>
但是有没有一种方法可以真正验证我的证书?
答案 0 :(得分:0)
首先:您需要配置客户端应用程序以信任服务器的自签名证书
SSLContext具有一个load_verify_locations
方法,该方法使您可以指定自定义的自签名根证书(请参见load_verify_locations的Python文档)。只需加载要连接的服务器的自签名根证书(或服务器证书本身,如果没有根证书/信任链)。
ssl_ctx.load_verify_locations(cafile='/path/to/your/root_ca.pem`)
请注意,如果要将同一客户端/上下文连接到具有公共证书的其他服务器,则还需要添加这些公共服务器的根证书。
另请参阅此Python文档段落以获取更多信息:client-side operations。
第二:您正在指定客户端证书,确定要吗?
您正在使用的方法load_cert_chain
将此证书作为客户端证书加载,以执行双向握手(请参阅Mutual Authentication)。通常,您仅检查服务器的证书以验证其身份并在应用程序层上对客户端进行身份验证(例如,用户/通过)。因此,您甚至不需要这样做(除非您知道自己在做什么,并且想通过客户端证书控制对服务的访问)。
最后: 我强烈建议不要禁用证书验证这一常被提及的解决方法。您只需要跳过身份验证,就可以使中间人受到攻击,并打败使用tls的主要目的。