如何让 python 信任我服务器的 TLS 自签名证书:ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败

2022-01-19 00:00:00 python sockets ssl network-programming

问题描述

这不是 这篇文章的重复.我在那里尝试了解决方案,但在我的情况下没有任何效果.

This is not a duplicate for this post. I tried the solutions there and nothing works in my case.

我使用的是 Windows 和 Python 3.6.5.我有一个用于 TLS 客户端的 python 脚本.我需要连接的服务器使用自签名证书.当我尝试使用我的脚本连接到它时,我收到此错误:

I am using Windows and Python 3.6.5. I have a python script for a TLS client. The server I need to connect to uses a self-signed certificate. When I try to connect to it using my script, I get this error:

ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)

我需要解析证书.我尝试将服务器的证书 .pem 内容添加到名为:cacert.pem 的文件中,该文件位于:C:Python36Libsite-packagescertifi 并再次运行程序.没变化.这是我的脚本.请帮助我让客户端对此服务器例外,因为我信任它的证书.

I need to parse the certificate. I tried to add my server's certificate .pem content to file named: cacert.pem which is in: C:Python36Libsite-packagescertifi and run the program again. Nothing change. Here is my scripot. Please help me to make the client make exception for this server as I trust its certificate.

import socket, ssl
import itertools

context = ssl.SSLContext() 
context.verify_mode = ssl.CERT_OPTIONAL 
context.check_hostname = False

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
domain="192.168.56.3" # my server
ssl_sock = context.wrap_socket(s, server_hostname=domain)
ssl_sock.connect((domain, 443))

print("====== peer's certificate ======")
try:
    cert = ssl_sock.getpeercert()
    print(cert)
except SSLError as e:
    print("Error: ",e)
ssl_sock.close()


解决方案

这个问题已经闲置了一段时间,但是以防有人仍然在努力通过Python连接到具有自签名证书的服务器 ssl 库:

This question has been idle for a while, but in case somebody is still struggling with connecting to a server with a self-signed certificate via Python ssl library:

您可以使用 SSLContextload_verify_locations 方法来指定自定义自签名根证书(请参阅 用于 load_verify_locations 的 Python 文档).

You can use the load_verify_locations method of SSLContext to specify custom self-signed root certs (see Python Docs for load_verify_locations).

上述代码可以扩展如下:

The forementioned code could be extended as follows:

...

context = ssl.SSLContext() 
context.verify_mode = ssl.CERT_OPTIONAL 
context.check_hostname = False

context.load_verify_locations(cafile='/path/to/your/cacert.pem')

...

请注意,如果您想使用具有相同客户端/上下文的公共证书连接到其他服务器,您还需要包含公共根证书.(例如,您可以将 cacert.pem 内容附加到 certifi 根证书并引用该文件夹/路径).

Be aware that you also need to include public root certs in case you want to connect to other servers with public certificates with the same client/context. (you could for example append your cacert.pem content to the certifi root certificates and reference that folder / path instead).

有关更多信息,另请参阅此 Python 文档段落:client端操作.

See also this Python docs paragraph for more information: client-side operations.

相关文章