エラーメッセージ
[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
このエラーの意味
サーバーが、RFC 5746 の安全な再ネゴシエーション拡張を使わずに TLS 1.2 以前をネゴシエートしました。OpenSSL 3 のクライアントは、デフォルトでこのようなサーバーを拒否します。従来の再ネゴシエーションでは、中間者攻撃者がクライアントのリクエストの前に自分のデータを差し込めたためです(CVE-2009-3555)。Python はこのデフォルトを引き継ぐため、ハンドシェイク中に接続が失敗します。
発生する理由
古いサーバーやアプライアンスの TLS スタック
よくある古い Windows Server のリリース、従来型の Java サーバー、ERP システム、ネットワーク機器、一部の政府機関や銀行のエンドポイントでは、RFC 5746 に対応しないままの TLS 実装が今も動いています。
RFC 5746 に対応していない、TLS を終端するミドルボックス
よくある古いロードバランサーやプロキシ(F5 BIG-IP や企業向けプロキシの一部のバージョン)は、最新のバックエンドの前で TLS を終端し、クライアントには自身の古い動作を見せます。
クライアントが OpenSSL 3 に移行した
よくある同じサーバーが、OpenSSL 1.1.1 ベースの Python ビルドでは動作していました。Python、OS、コンテナーのベースイメージをアップグレードしたことで、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.
一時的な回避策:1 つのホストに限って許可する
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)