带有 Python SSL 套接字的自签名证书

Posted

技术标签:

【中文标题】带有 Python SSL 套接字的自签名证书【英文标题】:Self signed Certificate with Python SSL socket 【发布时间】:2021-10-22 01:15:51 【问题描述】:

我使用通过以下命令生成的自签名证书:

sudo make-ssl-cert generate-default-snakeoil 

并将其复制到我的主目录。 如果我在服务器端运行以下命令:

from socket import socket, AF_INET, SOCK_STREAM
import ssl

def main():
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    context.verify_mode = ssl.CERT_REQUIRED
    context.load_cert_chain('/home/hfurmans/ssl-cert-snakeoil.pem', '/home/hfurmans/ssl-cert-snakeoil.key')

    host = "myipaddress"
    port = 5432
    my_socket = socket(AF_INET, SOCK_STREAM)
    my_socket.bind((host, port))
    my_socket.listen(1)
    my_socket = context.wrap_socket(my_socket, server_side=True)
    conn, addr = my_socket.accept()
    print("Connection from: " + str(addr))
    data = conn.recv(1024).decode()
    print(data)
    print("from connected user: " + str(data))
    data = str(data).upper()
    print("sending: " + str(data))
    conn.send(data.encode())
    conn.close()

if __name__ == "__main__":
    main()

我替换了我的 IP 地址。但是它们在服务器和客户端上是相同的。 这是客户端代码:

import socket
import ssl

hostname = "myipaddress"
context = ssl.create_default_context()

sock = socket.create_connection((hostname, 5432))
ssock = context.wrap_socket(sock, server_hostname=hostname)
print(ssock.version())
ssock.send("test")

如果我同时运行这两个脚本,我会收到以下错误。 这是客户端错误:

bash-3.2$ python3 client.py 
Traceback (most recent call last):
  File "client.py", line 8, in <module>
    ssock = context.wrap_socket(sock, server_hostname=hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 1040, in _create
    self.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1108)

这是服务器错误:

Traceback (most recent call last):
  File "server.py", line 27, in <module>
    main()
  File "server.py", line 16, in main
    conn, addr = my_socket.accept()
  File "/usr/lib/python3.6/ssl.py", line 1125, in accept
    server_side=True)
  File "/usr/lib/python3.6/ssl.py", line 407, in wrap_socket
    _context=self, _session=session)
  File "/usr/lib/python3.6/ssl.py", line 817, in __init__
    self.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 1077, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:852)

【问题讨论】:

我将证书文件从服务器复制到客户端。出现新错误:IP 地址不匹配 【参考方案1】:

自签名证书是一种伪装 CA 是证书本身。 所以我们必须事先向客户提供这个证书 以便在遇到它时信任它。

在客户端中,在创建 SSL 上下文之后, 我尝试了类似于

context.load_verify_locations('/home/hfurmans/ssl-cert-snakeoil.pem')

它奏效了。 (https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_verify_locations)

我只需要删除context.verify_mode = ssl.CERT_REQUIRED 服务器,因为我没有为我的客户提供自己的证书, 但这不是您的问题中报告的问题。


当然,要使所有这些工作,您的证书必须具有 正确的通用名称。 如果客户端连接到myipaddress(作为主机名), 那么证书的公用名也必须是myipaddress

【讨论】:

如何将公用名与自签名证书连接起来? @umgefahren 我不知道 make-ssl-cert 但是当我使用 openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes 时,此命令会提示输入许多信息,包括通用名称。

以上是关于带有 Python SSL 套接字的自签名证书的主要内容,如果未能解决你的问题,请参考以下文章

如何添加自签名SSL证书 自签名SSL证书存风险

自签名SSL证书介绍及其缺点

MAC申请自签名的ssl证书

企业为啥不能使用自签名SSL证书?

79) nginx添加linux自签ssl证书

自己生成的SSL证书与购买的SSL证书有啥区别?