Python 3.10运行SSL连接代码报SSLZeroReturnError如何修复
问题原因
同OpenSSL版本下Python 3.7和3.10表现不一致,核心是Python 3.10对ssl模块的默认安全策略做了大幅收紧,加上你使用的ssl.wrap_socket()本身是早已被标记废弃的旧接口,3.10版本中该接口的默认参数不再兼容旧版本的宽松配置:
- Python 3.7中
wrap_socket默认上下文最低支持TLS 1.0,默认不强制发送SNI扩展,允许使用大量旧加密套件,证书校验默认关闭 - Python 3.10搭配OpenSSL 3.0时,默认上下文最低只支持TLS 1.2,剔除了所有被判定为不安全的加密套件,安全校验规则更严格
握手阶段协议、加密套件或扩展不匹配时,服务端会直接断开TCP连接,就会抛出SSLZeroReturnError: TLS/SSL connection has been closed (EOF)错误。
修复方法
弃用废弃的wrap_socket直接调用方式,手动创建可配置的SSL上下文,根据服务端支持的协议版本调整参数即可,替换后的参考代码如下:
import socket import ssl import sys # 创建TLS客户端上下文 context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) # 测试环境临时关闭证书校验,生产环境请移除这两行配置,开启证书校验 context.check_hostname = False context.verify_mode = ssl.CERT_NONE # 调整OpenSSL安全等级为1,兼容旧加密套件 context.set_ciphers('DEFAULT:@SECLEVEL=1') # 如果服务端仅支持TLS 1.0/1.1,取消下行注释调低最低支持版本,支持TLS1.2+的服务端无需修改 # context.minimum_version = ssl.TLSVersion.TLSv1 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 传入server_hostname参数自动发送SNI扩展,适配虚拟主机部署的SSL服务 ssl_socket = context.wrap_socket(sock, server_hostname=sys.argv[1]) ssl_socket.connect((sys.argv[1], int(sys.argv[2])))
配置说明
- 优先确认服务端支持的最高TLS版本,如果服务端已经支持TLS 1.2及以上,不要调低最低TLS版本,保持默认配置即可获得更高安全性
@SECLEVEL=1是OpenSSL 3.0的安全等级配置,等级1允许使用80位安全强度的加密算法,可兼容大部分老旧SSL服务;非极端兼容场景不要把等级调到0,避免启用存在已知漏洞的弱加密算法- 生产环境部署时必须开启证书校验:将
check_hostname设为True,verify_mode设为ssl.CERT_REQUIRED,同时通过context.load_verify_locations()加载服务端证书对应的可信CA证书,避免中间人攻击风险 - 旧版
wrap_socket接口不会自动携带SNI扩展,很多多域名部署的SSL服务端没有收到SNI时会直接断开连接,这也是常见的握手失败原因,手动创建上下文时传入server_hostname参数即可解决该问题
内容的提问来源于stack exchange,提问作者python3.789
相关产品推荐
相关产品推荐

