URLError: <urlopen error [SSL:
UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation
disabled (_ssl.c:1131)>
上記は、セキュリティリスクのあるhttpsアドレスを開いたときに発生するエラーとなる。
SSLプロトコルの不具合で、中間者攻撃に使用される脆弱性のためopenssl側で無効化されている。OpenSSL
3.0.0からデフォルトで無効化された。
本来はサーバー側をアップデートするのが筋だが、なかなかそういうわけにもいかないことも多い。リスクを承知で、クライアント側の無効状態を解除する方法をメモ。
環境は以下の通り。
$ python -c 'import ssl; print(ssl.OPENSSL_VERSION)'
OpenSSL 3.0.2 15 Mar 2022
$ python --version
Python 3.8.10
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
Codename: jammy
回避策A: opensslの設定変更
opensslの設定を変更する方法。
/etc/ssl/openssl.conf
を編集して、system_default_sect
セクションにOptions
= UnsafeLegacyRenegotiation
設定を追加する。
# /etc/ssl/openssl.conf
...
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
CipherString = DEFAULT:@SECLEVEL=2
Options = UnsafeLegacyRenegotiation
ただし、/etc/ssl/openssl.conf
を直接編集すると、システム全体に適用されてしまうので流石にそれはまずい。
実際は別の設定ファイルを用意して、環境変数でpythonプログラムへ渡してやると良い。
$ cp /etc/ssl/openssl.conf openssl_unsecure.conf
$ echo -e "Options = UnsafeLegacyRenegotiation\n" >> openssl_unsecure.conf
$ OPENSSL_CONF=/path/to/openssl_unsecure.conf python cherry.py
回避策B: プログラム改修
sslのオプションに0x4
フラグを追加してやると回避できる。
開発版ではssl.OP_LEGACY_SERVER_CONNECT
定数が追加されているが、現行バージョン3.10でも使用できないので直接、値を指定する。
import urllib.request
import ssl
ctx = ssl.create_default_context()
ctx.options |= 0x4 # ssl.OP_LEGACY_SERVER_CONNECT
resposne = urllib.request.urlopen('https://...', context=ctx)
...
build_opener
を使う場合は、HTTPSHandler
を作成してやる。
opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx))
...
開発版でのOP_LEGACY_SERVER_CONNECT
についての記載。
.. data:: OP_LEGACY_SERVER_CONNECT
Allow legacy insecure renegotiation between OpenSSL and unpatched servers
only.
This option is only available with OpenSSL 0.9.8m and later, and is disabled
in default context since OpenSSL 3.0.0.
.. versionadded:: 3.11
以上。
古いpython2向けのスクリプトをpython3向けへ移植している時に発生した。