无证书情况下能否在客户端与服务器间建立SSL Socket?
无证书SSL Socket能否实现?
我们需要在客户端与服务器之间建立仅加密通信、无需身份验证的SSL连接,目的是防止(至少阻碍)通信被窃听。限制条件包括:
- 客户端/服务器进程生命周期较短,运行在多台机器上,可能未连接互联网
- 所有机器使用相同的文件/代码,因此“私钥”会成为公知信息,失去私有属性
现有代码
server.py
import socket import ssl address = ('localhost', 12345) context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.verify_mode = ssl.CERT_NONE with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as unsecured_socket: unsecured_socket.bind(address) unsecured_socket.listen(5) with context.wrap_socket(unsecured_socket, server_side=True) as sock: conn, addr = sock.accept() print(f"Accepted: {addr}")
client.py
import socket import ssl address = ('localhost', 12345) context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) context.check_hostname = False context.verify_mode = ssl.CERT_NONE with socket.create_connection(address) as unsecured_socket: with context.wrap_socket(unsecured_socket) as sock: print(sock.version())
运行报错
服务器端错误
Traceback (most recent call last): File "C:/experiments/server.py", line 13, in <module> conn, addr = sock.accept() File "C:\Program Files\Python313\Lib\ssl.py", line 1418, in accept newsock = self.context.wrap_socket(newsock, File "C:\Program Files\Python313\Lib\ssl.py", line 455, in wrap_socket return self.sslsocket_class._create( File "C:\Program Files\Python313\Lib\ssl.py", line 1076, in _create self.do_handshake() File "C:\Program Files\Python313\Lib\ssl.py", line 1372, in do_handshake self._sslobj.do_handshake() ssl.SSLError: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1028)
客户端错误
Traceback (most recent call last): File "C:\experiments\client.py", line 11, in <module> with context.wrap_socket(unsecured_socket) as sock: File "C:\Program Files\Python313\Lib\ssl.py", line 455, in wrap_socket return self.sslsocket_class._create( File "C:\Program Files\Python313\Lib\ssl.py", line 1076, in _create self.do_handshake() File "C:\Program Files\Python313\Lib\ssl.py", line 1372, in do_handshake self._sslobj.do_handshake() ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1028)
问题原因及解决方案
报错核心原因是:默认TLS配置中,服务器需要证书完成密钥交换,我们未提供证书,导致无可用共享加密套件。要实现无证书加密,需使用**匿名Diffie-Hellman(ADH)**系列加密套件,这类套件无需证书即可完成密钥协商。
修改后的代码如下:
修正后的server.py
import socket import ssl address = ('localhost', 12345) context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.verify_mode = ssl.CERT_NONE # 添加匿名加密套件 context.set_ciphers('ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256') with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as unsecured_socket: unsecured_socket.bind(address) unsecured_socket.listen(5) with context.wrap_socket(unsecured_socket, server_side=True) as sock: conn, addr = sock.accept() print(f"Accepted: {addr}") # 测试发送数据 conn.sendall(b"Hello from server") data = conn.recv(1024) print(f"Received: {data.decode()}")
修正后的client.py
import socket import ssl address = ('localhost', 12345) context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) context.check_hostname = False context.verify_mode = ssl.CERT_NONE # 添加和服务器一致的匿名加密套件 context.set_ciphers('ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256') with socket.create_connection(address) as unsecured_socket: with context.wrap_socket(unsecured_socket) as sock: print(f"TLS版本: {sock.version()}") # 测试接收和发送数据 data = sock.recv(1024) print(f"Received: {data.decode()}") sock.sendall(b"Hello from client")
注意事项
- 匿名加密套件安全性低于带证书的套件,无法验证通信方身份,存在中间人攻击风险,但能满足“仅加密防窃听”的需求
- 客户端和服务器必须使用一致的加密套件列表,否则仍会出现无共享套件的错误
- 不同Python或OpenSSL版本支持的匿名套件可能不同,可通过
openssl ciphers -v | grep ADH命令查看当前环境支持的ADH套件
内容的提问来源于stack exchange,提问作者AJNeufeld
相关产品推荐
相关产品推荐

