错误信息
[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled
出现在链接 OpenSSL 3.0 或更高版本的 Python 上(2022年以来的大多数 Python 构建版本);OpenSSL 1.1.1 仍允许连接这类服务器。后面跟着源代码位置,例如“(_ssl.c:1082)”。
Python ssl module (OpenSSL 3) — ssl.SSLError, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED
含义
服务器协商的是 TLS 1.2 或更早的版本,且不支持 RFC 5746 的安全重新协商扩展。OpenSSL 3 客户端默认拒绝这类服务器,因为旧式重新协商允许中间人把自己的数据拼接到客户端请求的前面(CVE-2009-3555)。Python 继承了这个默认设置,因此连接在握手期间失败。
原因
服务器或专用设备的 TLS 栈已过时
常见旧版 Windows Server、老旧的 Java 服务器、ERP 系统、网络设备以及一些政府或银行端点,仍在运行从未支持 RFC 5746 的 TLS 实现。
负责终止 TLS 的中间设备不支持 RFC 5746
常见旧的负载均衡器和代理(某些版本的 F5 BIG-IP 和企业代理)为现代后端终止 TLS,向客户端呈现的却是它们自己的旧式行为。
客户端改用了 OpenSSL 3
常见同一台服务器在基于 OpenSSL 1.1.1 的 Python 构建版本上可以正常使用;升级 Python、操作系统或容器基础镜像时,换上了新的 OpenSSL 及其更严格的默认设置。
修复方法
- 1.
确认服务器不支持安全重新协商
对于这类服务器,openssl s_client 会报告“Secure Renegotiation IS NOT supported”。
bash openssl s_client -connect legacy.example.com:443 -servername legacy.example.com </dev/null 2>/dev/null \ | grep -i 'secure renegotiation' # "Secure Renegotiation IS NOT supported" confirms the server lacks RFC 5746 - 2.
修复服务器
更新服务器的 TLS 栈或固件,或者提供 TLS 1.3,就能为所有客户端消除这个问题。
text Server / appliance owners: update the TLS stack or firmware to any release supporting RFC 5746 (every mainstream TLS library since 2010), or enable TLS 1.3, which has no renegotiation at all. - 3.
临时解决办法:只对一台主机放行
ssl.OP_LEGACY_SERVER_CONNECT(Python 3.12+)只在这一个上下文中重新允许连接这类服务器。它会让该主机重新面临重新协商拼接风险,因此不要全局设置它,也不要通过系统的 OpenSSL 配置设置它。
python # Temporary workaround for one legacy host only (Python 3.12+: ssl.OP_LEGACY_SERVER_CONNECT) import ssl, urllib.request ctx = ssl.create_default_context() ctx.options |= ssl.OP_LEGACY_SERVER_CONNECT urllib.request.urlopen("https://legacy.example.com/", context=ctx)