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
Um proxy corporativo ou antivírus intercepta o HTTPS
comumA equipe de TI instala a raiz de interceptação no repositório de certificados do Windows ou do macOS, por isso os navegadores funcionam. O OpenSSL do Python e as bibliotecas que usam o bundle do certifi não leem esses repositórios.
O requests, o pip ou o httpx verificam com o certifi
comumO certifi contém apenas as raízes públicas da Mozilla. Adicionar a raiz da empresa ao repositório do sistema não altera o arquivo do certifi, e uma atualização do certifi via pip sobrescreve as edições manuais.
Um serviço interno envia a própria raiz privada
ocasionalAPIs internas assinadas por uma CA da empresa que enviam a raiz na cadeia continuam precisando dessa raiz configurada no cliente.
O conda, o pyenv ou um ambiente virtual com bundle próprio
ocasionalO conda traz o próprio OpenSSL e o próprio bundle de CAs; uma correção aplicada ao Python do sistema não chega até ele.
Como corrigir
- 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.
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.
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.
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
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local…Python ssl module (OpenSSL)[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certifi…Python ssl module (OpenSSL)There was a problem confirming the ssl certificate: [SSL: CERTIFICATE_VERIFY_FA…pipcurl: (60) SSL certificate problem: self-signed certificate in certificate chaincurl (OpenSSL backend)