Pular para o conteúdo
ecdsa.com
requests / urllib3 (Python)Python (cryptography)

Mensagem de erro

Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate

Também aparece como

  • requests.exceptions.SSLError: HTTPSConnectionPool(host='api.example.com', port=8443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate

O host, a porta e o caminho da URL vêm da sua requisição. O motivo mais interno varia (“self-signed certificate in certificate chain”, “Hostname mismatch…”, “certificate has expired”), e a linha termina com uma localização no código-fonte, como “(_ssl.c:1082)')))”.

requests / urllib3 (Python) — requests.exceptions.SSLError wrapping urllib3 MaxRetryError

O que significa

O requests pediu uma conexão ao urllib3, o handshake TLS falhou na verificação do certificado e o urllib3 desistiu (com o padrão do requests, que não faz novas tentativas, já depois da primeira tentativa). A parte útil está entre parênteses: aqui, o OpenSSL não encontrou o emissor no bundle de CAs que o requests usa, que por padrão é a cópia das raízes da Mozilla distribuída pelo certifi, e não o repositório de certificados do sistema operacional.

Por que acontece

Como corrigir

  1. 1.

    Passar o bundle certo com verify=

    O verify aceita o caminho de um arquivo de bundle de CAs ou de um diretório de CAs indexado por hash; as verificações de nome de host e de datas continuam ativas.

    python
    import requests
    
    # A CA file (or a directory prepared with c_rehash) for this call
    requests.get("https://api.example.com/", verify="/etc/ssl/certs/ca-certificates.crt")
  2. 2.

    Definir REQUESTS_CA_BUNDLE para o processo

    Apontar essa variável para o bundle do sistema (depois de instalar sua CA nele) faz toda chamada do requests nesse processo confiar nas mesmas raízes que o curl e as ferramentas do sistema operacional.

    bash
    # For every requests call in the process (also honoured: CURL_CA_BUNDLE)
    export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt   # Debian/Ubuntu system bundle
    python3 app.py
  3. 3.

    Usar o trust store do sistema operacional

    truststore.inject_into_ssl() na inicialização faz o requests verificar pelo sistema operacional, de modo que as raízes implantadas pela TI funcionam sem que seja preciso manter bundles.

    python
    # pip install truststore==0.10.5 — requests then verifies with the OS trust store
    import truststore
    truststore.inject_into_ssl()
    
    import requests
    requests.get("https://api.example.com/")
  4. 4.

    Configurar uma sessão (Session) uma única vez

    Em aplicativos, defina Session.verify como um bundle que contenha as raízes públicas mais a raiz da empresa e reutilize a sessão.

    python
    import requests
    
    session = requests.Session()
    session.verify = "/etc/ssl/private-ca/corp-ca-bundle.pem"   # public roots + company root
    session.get("https://api.example.com/")

Erros relacionados

Ver toda a base de erros de assinatura