Сообщение об ошибке
[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled
Появляется в Python, собранном с OpenSSL 3.0 или новее (большинство сборок Python с 2022 года); 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-системах, на сетевых устройствах и некоторых государственных или банковских эндпоинтах до сих пор работают реализации TLS, в которые так и не добавили поддержку RFC 5746.
Промежуточное устройство без RFC 5746, завершающее TLS
частоСтарые балансировщики нагрузки и прокси (некоторые версии F5 BIG-IP и корпоративных прокси) завершают TLS перед современными бэкендами и показывают клиентам собственное устаревшее поведение.
Клиент перешёл на OpenSSL 3
частоТот же сервер работал со сборками Python на OpenSSL 1.1.1; при обновлении 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)