Pular para o conteúdo
ecdsa.com
Python ssl module (OpenSSL)Python (cryptography)

Mensagem de erro

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

Também aparece como

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

O OpenSSL 3 imprime “self-signed”, e o OpenSSL 1.1.1, “self signed”; o Python acrescenta uma localização no código-fonte, como “(_ssl.c:1082)”. Pelo urllib, a mensagem aparece dentro de “<urlopen error …>”; pelo requests, dentro de “Max retries exceeded … (Caused by SSLError(…))”.

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

O que significa

A cadeia que o servidor apresentou termina em um certificado raiz autoassinado que não está entre as CAs em que este processo Python confia. A cadeia em si está completa; a raiz é que é desconhecida. Quando isso acontece com sites públicos como pypi.org ou api.github.com, a raiz pertence a um proxy com inspeção de TLS ou a um antivírus na sua rede ou na sua máquina.

Por que acontece

Como corrigir

  1. 1.

    Descobrir de quem é a raiz

    Imprima a cadeia de um host público. Uma raiz com o nome da sua empresa ou de um produto de segurança é a raiz em que você deve confiar; um nome desconhecido em uma rede não confiável é motivo para parar, não para confiar nela.

    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.

    Verificar com o trust store do sistema operacional

    truststore.inject_into_ssl() faz o TLS do Python usar o trust store do sistema operacional, que já contém as raízes implantadas pela sua organização. É a correção mais limpa em máquinas Windows e macOS gerenciadas.

    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.

    Montar um bundle com as raízes públicas mais a sua raiz

    REQUESTS_CA_BUNDLE (requests) e SSL_CERT_FILE (ssl, urllib, httpx) substituem o bundle padrão; portanto, concatene as raízes do certifi com a raiz da empresa em vez de apontar só para a raiz da empresa.

    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: definir a opção específica dele

    O conda lê ssl_verify do .condarc; aponte essa opção para o bundle combinado para que conda install e conda update funcionem atrás do proxy.

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

Erros relacionados

Ver toda a base de erros de assinatura