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

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

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

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

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

Python добавляет место в исходном коде на C, например «(_ssl.c:1082)». Не путайте эту ошибку с «self-signed certificate in certificate chain»: та означает цепочку CA, которая заканчивается недоверенным корневым сертификатом. OpenSSL 1.1.1 пишет «self signed».

Python ssl module (OpenSSL) — ssl.SSLCertVerificationError, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (18)

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

Сервер предъявил единственный самоподписанный сертификат (его издатель — он сам), которого нет в наборе доверенных CA этого контекста. Искать нечего: за сертификатом нет CA, поэтому OpenSSL выдаёт ошибку на глубине 0. Это типично для серверов разработки, специализированных устройств и свежих установок; решение — осознанно доверять этому сертификату или заменить его.

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

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

  1. 1.

    Доверяйте только этому сертификату и только в этом клиенте

    Загрузите собственный сертификат сервера как cafile. Проверки имени хоста и срока действия остаются включёнными, а принимается только этот конкретный сертификат.

    python
    import ssl, urllib.request
    
    # Trust exactly this certificate (fetched and fingerprint-checked out of band)
    ctx = ssl.create_default_context(cafile="api.example.com.pem")
    urllib.request.urlopen("https://api.example.com:8443/", context=ctx)
  2. 2.

    Получите сертификат и сверьте его отпечаток

    Прежде чем доверять файлу, сверьте отпечаток SHA-256 со значением, которое показывает консоль устройства или сообщает его администратор.

    bash
    openssl s_client -connect api.example.com:8443 -servername api.example.com </dev/null 2>/dev/null \
      | openssl x509 -out api.example.com.pem
    openssl x509 -in api.example.com.pem -noout -fingerprint -sha256   # compare with the server's console
  3. 3.

    При разработке: используйте вместо этого локальный CA

    Локальный CA позволяет доверять одному корневому сертификату и выпускать правильно подписанные сертификаты для всех хостов разработки, поэтому ни одному клиенту не нужны исключения для отдельных сертификатов.

    bash
    # Development: one local CA, many certificates (mkcert installs the CA for you)
    mkcert -install
    mkcert api.example.test
    export SSL_CERT_FILE="$(mkcert -CAROOT)/rootCA.pem"
  4. 4.

    Временная диагностика: отключите проверку в тесте

    check_hostname = False и CERT_NONE отключают все проверки и принимают любой сертификат, в том числе предъявленный злоумышленником. Используйте эту настройку только для того, чтобы убедиться, что проблема исключительно в доверии, а затем уберите её.

    python
    # Temporary diagnostic only: proves trust is the sole problem. Never ship this.
    import ssl
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

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

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