Python ssl module (OpenSSL, security level 2)Python cryptography 库
错误信息
[SSL: DH_KEY_TOO_SMALL] dh key too small
后面跟着源代码位置,例如“(_ssl.c:1082)”。curl 和其他基于 OpenSSL 的客户端会把同一原因打印为“dh key too small”。
Python ssl module (OpenSSL, security level 2) — ssl.SSLError, SSL_R_DH_KEY_TOO_SMALL
含义
服务器选择了有限域 Diffie-Hellman(DHE)密钥交换,而所用的组小于客户端可接受的大小,通常是 1024 位。Python 3.10 及更高版本使用 OpenSSL 安全级别 2,要求 DH 至少为 2048 位,因此客户端中止了握手。问题不在服务器证书上。
原因
服务器使用 1024 位的 DH 组
常见旧版 Apache httpd(2.4.7 之前使用固定的 1024 位参数)、较旧的基于 Java 的服务器,以及仍在加载多年前生成的 dhparam 文件的配置。Logjam 研究(2015年)表明,1024 位 DH 已在资金充足的攻击者的能力范围之内。
Python 更严格的默认安全级别
常见Python 3.10 把默认值提高到了 OpenSSL 安全级别 2。在 Python 3.9 上能正常连接的代码,升级后可能会失败,尽管服务器没有任何变化。
嵌入式设备和专用设备
偶见打印机、PBX 系统和工业设备的管理界面,往往只提供使用较小 DH 组的 DHE。
修复方法
- 1.
确认密钥交换使用的位数
用 openssl s_client 在安全级别 1 下连接一次,查看“Server Temp Key”。
bash # "Server Temp Key: DH, 1024 bits" confirms the weak group openssl s_client -connect legacy.example.com:443 -servername legacy.example.com \ -cipher 'DEFAULT:@SECLEVEL=1' </dev/null 2>/dev/null | grep 'Server Temp Key' - 2.
服务器所有者:使用 ECDHE 或 2048 位的组
优先使用 ECDHE 套件(以及 TLS 1.3);如果必须使用 DHE,就配置至少 2048 位的 RFC 7919 组。
text # nginx: prefer ECDHE; if DHE must stay, use a 2048-bit (or larger) group ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_dhparam /etc/nginx/ffdhe2048.pem; # RFC 7919 group - 3.
临时解决办法:只为一台主机降低安全级别
在专用的上下文中设置“DEFAULT:@SECLEVEL=1”,只对该主机接受 1024 位 DH。不要把它用在共享或默认的上下文中:它还会接受其他弱参数。
python # Temporary workaround for one legacy host: security level 1 accepts 1024-bit DH import ssl, urllib.request ctx = ssl.create_default_context() ctx.set_ciphers("DEFAULT:@SECLEVEL=1") urllib.request.urlopen("https://legacy.example.com/", context=ctx)
相关错误
[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failurePython ssl module (OpenSSL)[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabledPython ssl module (OpenSSL 3)curl: (35) TLS connect error: error:0A000410:SSL routines::ssl/tls alert handsh…curl (OpenSSL backend)