Перейти к содержимому
ecdsa.com
Python ssl module (OpenSSL)Python: пакет cryptography

Сообщение об ошибке

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain

Также выводится как

  • [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain

OpenSSL 3 пишет «self-signed», OpenSSL 1.1.1 — «self signed»; Python добавляет место в исходном коде, например «(_ssl.c:1082)». При вызове через urllib сообщение оказывается внутри «<urlopen error …>», через requests — внутри «Max retries exceeded … (Caused by SSLError(…))».

Python ssl module (OpenSSL) — ssl.SSLCertVerificationError, X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN (19)

Что это означает

Цепочка, которую предъявил сервер, заканчивается самоподписанным корневым сертификатом, который не входит в число CA, доверенных для этого процесса Python. Сама цепочка полная, просто корневой сертификат неизвестен. Если это происходит с публичными сайтами вроде pypi.org или api.github.com, корневой сертификат принадлежит прокси или антивирусу с инспекцией TLS в вашей сети или на вашей машине.

Почему это происходит

Как исправить

  1. 1.

    Выясните, чей это корневой сертификат

    Выведите цепочку для публичного хоста. Если корневой сертификат назван по имени вашей компании или средства защиты, доверять нужно именно ему; незнакомое имя в недоверенной сети — повод остановиться, а не доверять.

    bash
    openssl s_client -connect pypi.org:443 -servername pypi.org -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:'
    # A top certificate named after your company or a security vendor = interception proxy
  2. 2.

    Используйте для проверки хранилище доверенных сертификатов операционной системы

    truststore.inject_into_ssl() переключает TLS в Python на хранилище доверенных сертификатов ОС, где уже есть корневые сертификаты, развёрнутые вашей организацией. Это самое чистое решение на управляемых машинах с Windows и macOS.

    python
    # pip install truststore==0.10.5
    import truststore
    truststore.inject_into_ssl()   # the proxy root deployed in the OS store is now trusted
    
    import requests
    requests.get("https://api.example.com/")
  3. 3.

    Соберите пакет с публичными корневыми сертификатами и вашим корневым сертификатом

    REQUESTS_CA_BUNDLE (requests) и SSL_CERT_FILE (ssl, urllib, httpx) заменяют пакет сертификатов по умолчанию, поэтому объедините корневые сертификаты certifi с корневым сертификатом компании, а не указывайте в переменной только корневой сертификат компании.

    bash
    # Keep the public roots and add the company/proxy root
    cat "$(python3 -m certifi)" corp-root-ca.pem > ~/.config/corp-ca-bundle.pem
    export REQUESTS_CA_BUNDLE=~/.config/corp-ca-bundle.pem   # requests
    export SSL_CERT_FILE=~/.config/corp-ca-bundle.pem        # ssl, urllib, httpx
  4. 4.

    conda: настройте собственный параметр conda

    conda читает ssl_verify из .condarc; укажите в этом параметре объединённый пакет сертификатов, чтобы conda install и conda update работали за прокси.

    bash
    # conda keeps its own OpenSSL and CA bundle
    conda config --set ssl_verify /path/to/corp-ca-bundle.pem

Связанные ошибки

Открыть всю базу ошибок подписей