Python Requests用TLSv1发Client Hello遭拒,求问题原因
问题:Python SSL连接异常,强制使用TLSv1导致被服务器拒绝
环境信息
- 基于Docker镜像
python:3.11.6-slim-bullseye搭建Python 3.11.6环境,用于Zeep服务连接 - OpenSSL版本:
OpenSSL 1.1.1w 11 Sep 2023
测试脚本
def test_connection(db_no_rollback): HTTPConnection.debuglevel = 1 # 初始化日志 logging.basicConfig() logging.getLogger().setLevel(logging.DEBUG) requests_log = logging.getLogger("requests.packages.urllib3") requests_log.setLevel(logging.DEBUG) requests_log.propagate = True import ssl, socket hostname = 'www.handlingandfulfilment.co.uk' # hostname = "www.growthpath.com.au" # context = ssl.create_default_context() context = ssl.SSLContext(ssl.PROTOCOL_TLS) # 创建默认上下文 context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 # 禁用TLS 1.0和1.1 with socket.create_connection((hostname, 443)) as sock: with context.wrap_socket(sock, server_hostname=hostname) as ssock: print(ssock.getpeercert()) assert True
现象
- 连接大部分正常主机时,Wireshark显示使用TLSv1.3发起Client Hello,符合预期:
6412 410.231952331 192.168.41.11 188.166.227.141 TLSv1.3 583 Client Hello
- 连接目标问题服务器时,Wireshark显示代码使用TLSv1发起Client Hello:
421 9.896938114 192.168.41.11 193.109.12.6 TLSv1 571 Client Hello
- 触发连接重置异常:
self = <ssl.SSLSocket [closed] fd=-1, family=2, type=1, proto=6>, block = False @_sslcopydoc def do_handshake(self, block=False): self._check_connected() timeout = self.gettimeout() try: if timeout == 0.0 and block: self.settimeout(None) > self._sslobj.do_handshake() E ConnectionResetError: [Errno 104] Connection reset by peer
- 确认异常原因是服务器拒绝TLSv1版本连接,且基于同一镜像的Kubernetes生产部署也存在相同问题,排除本地机器或办公网络影响。
核心疑问
代码中已明确禁用TLSv1和TLSv1.1,为何仍会尝试使用TLSv1协商连接?
更新:已找到可行解决方案
纯OpenSSL连接验证
执行以下命令可正常建立连接:
openssl s_client -connect www.handlingandfulfilment.co.uk:8079
返回结果显示使用TLSv1.2及对应加密套件:
New, TLSv1.2, Cipher is AES256-GCM-SHA384
最终可行代码
# 替代实现方式 # 创建socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((hostname, 443)) context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) import certifi context.load_verify_locations(certifi.where()) context.set_ciphers('ECDHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384:!aNULL:!MD5') wrappedSocket = context.wrap_socket(sock, server_hostname=hostname) assert wrappedSocket
当前代码已通过断言验证,但暂未明确原代码异常的具体原理。
内容的提问来源于stack exchange,提问作者Tim Richardson
相关产品推荐
相关产品推荐

