エラーメッセージ
[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
このエラーの意味
サーバーが、クライアントが受け入れるより小さいグループ(通常は 1024 ビット)で有限体 Diffie-Hellman(DHE)鍵交換を選択しました。Python 3.10 以降は OpenSSL のセキュリティレベル 2 を使い、2048 ビット以上の DH を必須とするため、クライアントがハンドシェイクを中止します。サーバーの証明書には問題はありません。
発生する理由
サーバーが 1024 ビットの DH グループを使っている
よくある古い Apache httpd のリリース(2.4.7 より前は固定の 1024 ビットのパラメーターを使用)、古い Java ベースのサーバー、何年も前に生成した dhparam ファイルをまだ読み込んでいる設定が該当します。Logjam の研究(2015年)で、1024 ビットの DH は資金力のある攻撃者なら破れる範囲にあることが示されました。
Python のより厳格なデフォルトのセキュリティレベル
よくあるPython 3.10 で、デフォルトが OpenSSL のセキュリティレベル 2 に引き上げられました。Python 3.9 では問題なく接続できていたコードが、サーバー側は何も変わっていないのに、アップグレード後に失敗することがあります。
組み込み機器とアプライアンス
ときどきプリンター、PBX システム、産業機器の管理インターフェースは、小さいグループの 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.
一時的な回避策:1 つのホストに限ってセキュリティレベルを下げる
専用のコンテキストで「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)