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

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

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate

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

  • ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate

Python добавляет место в исходном коде на C, например «(_ssl.c:1082)»; номер меняется от версии к версии Python и для диагностики ничего не значит. urllib оборачивает ошибку в «<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] …>», а requests и urllib3 — в «Max retries exceeded … (Caused by SSLError(…))».

Python ssl module (OpenSSL) — ssl.SSLCertVerificationError, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY (20)

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

Модуль ssl в Python попросил OpenSSL проверить сертификат сервера, и OpenSSL не нашёл издателя последнего сертификата цепочки среди сертификатов CA, загруженных в этот SSLContext. Сервер не обязательно настроен неправильно: часто этот Python просто использует не тот пакет сертификатов CA, что ваш браузер или операционная система, а то и пустой.

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

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

  1. 1.

    Сборки python.org для macOS: запустите Install Certificates.command

    Скрипт устанавливает certifi и создаёт на него ссылку как на пакет сертификатов для OpenSSL этого Python. После установки другой версии Python скрипт обязательно нужно запустить снова.

    bash
    # macOS, python.org installer: run once per installed Python version
    "/Applications/Python 3.14/Install Certificates.command"
  2. 2.

    Используйте хранилище доверенных сертификатов ОС через truststore

    truststore заставляет ssl.SSLContext проверять сертификаты средствами ОС (связка ключей в macOS, хранилище сертификатов Windows, системный пакет сертификатов в Linux), поэтому корневые сертификаты, развёрнутые вашим ИТ-отделом, работают и в Python. Это распространяется и на urllib3, requests и pip, причём pip использует truststore по умолчанию начиная с pip 24.2.

    python
    # pip install truststore==0.10.5  — verify with the OS trust store (Keychain, Windows store, Linux bundle)
    import truststore
    truststore.inject_into_ssl()   # call once at start-up, before creating connections
    
    import urllib.request
    urllib.request.urlopen("https://api.example.com/")
  3. 3.

    Явно загрузите CA для одного клиента

    В коде, который обращается к частному сервису, передайте cafile (или cadata) в ssl.create_default_context(). Контекст по-прежнему проверяет имена хостов и сроки действия.

    python
    import ssl, urllib.request
    
    ctx = ssl.create_default_context(cafile="/etc/ssl/private-ca/corp-root-ca.pem")
    urllib.request.urlopen("https://api.example.com/", context=ctx)
  4. 4.

    Проверьте и задайте путь к пакету сертификатов по умолчанию

    ssl.get_default_verify_paths() показывает, какие файл и каталог использует OpenSSL. SSL_CERT_FILE и SSL_CERT_DIR переопределяют их для процесса; укажите в них пакет сертификатов, который содержит и публичные корневые сертификаты, и ваш CA.

    bash
    # Where does this Python look by default?
    python3 -c "import ssl; print(ssl.get_default_verify_paths())"
    # Point OpenSSL-based clients at a bundle that includes your CA
    export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
  5. 5.

    Владельцам серверов: отправляйте полную цепочку

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

    bash
    # Server side: 1 certificate in the handshake = intermediate missing
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -c 'BEGIN CERTIFICATE'

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

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