🌐 Detecting your location…

Como corrigir ‘problema de certificado SSL: não é possível obter o certificado do emissor local’

⏱️7 min read  ·  1,524 words

SSL certificate problem: unable to get local issuer certificatesignifica que seu cliente não conseguiu construir uma cadeia de confiança do certificado do servidor para uma autoridade de certificação em que ele confia. A tentação é desabilitar a verificação. Não faça isso – isso remove totalmente a proteção contra interceptação. A solução real geralmente é simples.

O que o erro significa

Quando um cliente se conecta por TLS, o servidor apresenta seu certificado mais quaisquer certificados intermediários. O cliente deve vincular essa cadeia a uma raiz confiável em seu armazenamento local de CA. O erro aparece quando um link está faltando – ou o servidor não enviou o intermediário ou seu armazenamento confiável local está ausente ou desatualizado.

Diagnosticar isso inspecionando a corrente.

openssl s_client -connect example.com:443 -showcerts </dev/null

# Look for the verification result at the end:
#   Verify return code: 0 (ok)
#   Verify return code: 20 (unable to get local issuer certificate)
#   Verify return code: 21 (unable to verify the first certificate)

Código de retorno21 geralmente significa que o servidor é o culpado — ele não enviou seu certificado intermediário. Código de retorno20 geralmente significa que seu armazenamento confiável local é o problema.

Causa 1: O servidor não está enviando intermediários

Uma configuração incorreta comum do servidor. Os navegadores geralmente o ocultam porque armazenam em cache intermediários de visitas anteriores, de modo que o site “funciona no Chrome” enquanto o curl e o pipeline de CI falham.

# Count the certificates the server sends
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null \
  | grep -c "BEGIN CERTIFICATE"
# 1 means only the leaf — the intermediate is missing

Se você controla o servidor, conserte-o lá. O nginx precisa da folha e dos intermediários concatenados em um arquivo, nessa ordem.

# Correct order: leaf first, then intermediates
cat leaf.crt intermediate.crt > fullchain.crt
server {
    # Use the full chain, not just the leaf certificate
    ssl_certificate     /etc/ssl/certs/fullchain.crt;
    ssl_certificate_key /etc/ssl/private/privkey.key;
}

Certbotsfullchain.pem já contém a cadeia – apontando nginx paracert.pem em vez disso, é a causa mais frequente desse erro em sites Let’s Encrypt.

Causa 2: um pacote CA desatualizado ou ausente

Se a cadeia do servidor estiver completa, seu armazenamento confiável local estará obsoleto.

# Debian / Ubuntu
sudo apt update && sudo apt install --reinstall ca-certificates
sudo update-ca-certificates

# RHEL / Fedora
sudo dnf reinstall ca-certificates
sudo update-ca-trust

# Alpine (very common in Docker images)
apk add --no-cache ca-certificates
update-ca-certificates

# macOS
brew install ca-certificates
# or update curl, which bundles its own
brew install curl

Imagens mínimas do Docker são uma fonte frequente desse erro porque são fornecidas sem nenhum pacote CA. Adicionandoca-certificates à imagem geralmente resolve em uma linha.

Causa 3: Interceptação TLS Corporativa

Muitas redes corporativas interceptam o TLS, apresentando seu próprio certificado assinado por uma CA interna. Os navegadores funcionam porque o CA é instalado no nível do sistema operacional por meio do gerenciamento de dispositivos; ferramentas de linha de comando com seus próprios armazenamentos confiáveis, não.

A solução é adicionar a CA raiz corporativa ao armazenamento confiável relevante – não desabilitar a verificação.

# Capture the certificate the proxy is presenting
openssl s_client -showcerts -connect example.com:443 </dev/null \
  | openssl x509 -outform PEM > corp-ca.crt

# Inspect it to confirm what it is
openssl x509 -in corp-ca.crt -noout -subject -issuer -dates

# Install system-wide (Debian/Ubuntu)
sudo cp corp-ca.crt /usr/local/share/ca-certificates/corp-ca.crt
sudo update-ca-certificates

Peça ao seu departamento de TI o arquivo CA raiz oficial em vez de extraí-lo você mesmo sempre que possível – extrair de uma conexão ativa pressupõe que a conexão ainda não esteja comprometida.

Correções por ferramenta

enrolar

# Point at a specific bundle
curl --cacert /path/to/ca-bundle.crt https://example.com

# Or set it for the session
export CURL_CA_BUNDLE=/path/to/ca-bundle.crt

Git

# Correct fix: point Git at a valid bundle
git config --global http.sslCAInfo /path/to/ca-bundle.crt

# Scope it to one host if only that host is affected
git config --global http."https://internal.company.com/".sslCAInfo /path/to/corp-ca.crt

git config --global http.sslVerify false aparece em todos os resultados da pesquisa para esse erro. Ele desativa permanentemente a verificação de certificado para cada host do qual você clonou. Não use isso.

Node.js

# Add a CA to Node's trust store for this process
export NODE_EXTRA_CA_CERTS=/path/to/corp-ca.crt
node app.js
// Or per-request, which is more precise
import https from 'node:https';
import fs from 'node:fs';

const agent = new https.Agent({
  ca: fs.readFileSync('/path/to/corp-ca.crt'),
});

await fetch('https://internal.example.com', { agent });

NODE_TLS_REJECT_UNAUTHORIZED=0 desativa a verificação em todo o processo e o Node imprime um aviso dizendo exatamente isso. É aceitável em um teste local descartável e em nenhum outro lugar.

Píton

import certifi, requests

# Use certifi's bundle explicitly
requests.get('https://example.com', verify=certifi.where())

# Or a corporate CA
requests.get('https://internal.example.com', verify='/path/to/corp-ca.crt')
# Environment variables respected by requests and urllib3
export REQUESTS_CA_BUNDLE=/path/to/ca-bundle.crt
export SSL_CERT_FILE=/path/to/ca-bundle.crt

# Keep certifi current
pip install --upgrade certifi

Docker

FROM node:22-alpine

# Alpine ships without a CA bundle
RUN apk add --no-cache ca-certificates

# Add a corporate CA if you are behind interception
COPY corp-ca.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates

ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt

Causa 4: O certificado expirou

Verifique antes de assumir um problema de armazenamento confiável.

echo | openssl s_client -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates
# notBefore=...
# notAfter=...

Verifique também o relógio do cliente. Uma máquina com uma data muito errada rejeita certificados válidos como ainda não válidos ou expirados, e isso detecta contêineres e máquinas virtuais que foram suspensas.

date
timedatectl status    # Linux

Sequência Diagnóstica

  1. openssl s_client -connect host:443 -showcerts — leia o código de retorno de verificação
  2. Conte os certificados enviados. Um significa um intermediário ausente no servidor.
  3. Verifique as datas de validade e o relógio do sistema local.
  4. Compare com outra máquina ou rede – se funcionar lá, o problema é local.
  5. Verifique se o emissor é sua CA corporativa, o que indica interceptação.
  6. Atualizaçãoca-certificates e qualquer pacote específico de idioma.

Por que não apenas desativar a verificação

Porque a verificação do certificado é todo o mecanismo que impede que alguém na rede se faça passar pelo servidor com o qual você pensa que está conversando. Desativá-lo significa que qualquer intermediário pode ler e modificar o tráfego – incluindo credenciais, tokens e os pacotes que você está baixando.

O risco realista não é teórico. Um pipeline de CI com verificação desabilitada instalará com prazer um pacote de um registro personificado. A correção leva minutos; a consequência de ignorá-lo pode ser uma construção comprometida.

Perguntas Frequentes

P: Por que funciona no meu navegador, mas não no curl?
R: Os navegadores armazenam em cache certificados intermediários de conexões anteriores e podem buscar automaticamente os ausentes. curl não faz nada disso, então expõe um problema de cadeia do lado do servidor que os navegadores escondem.

P: Qual é a diferença entre o erro 20 e o erro 21?
R: 21 significa que o cliente não pôde verificar o primeiro certificado, normalmente porque os intermediários não foram enviados. 20 significa que o emissor não foi encontrado em seu armazenamento confiável local.

P: Onde está o pacote CA no meu sistema?
R: Geralmente/etc/ssl/certs/ca-certificates.crt no Debian e Ubuntu,/etc/pki/tls/certs/ca-bundle.crt no RHEL. Em Python,python -m certifi imprime o caminho que o certificado usa.

P: É seguro desabilitar a verificação apenas para desenvolvimento local?
R: Para um servidor local com um certificado autoassinado, adicione esse certificado ao seu armazenamento confiável — isso leva o mesmo tempo e não cria um hábito que o acompanha até a configuração de produção.

P: Meu CI funciona, mas a produção falha. Por que?
R: Quase sempre há diferença na imagem base. Imagens Slim e Alpine frequentemente omitemca-certificates inteiramente.

Conclusão

Este erro significa que a cadeia de confiança foi quebrada e existem apenas algumas causas:o servidor não está enviando seus certificados intermediários, seu pacote de CA local está ausente ou desatualizado, um proxy corporativo está interceptando o TLS com sua própria CA ou um certificado expirou. Diagnosticar comopenssl s_client e o código de retorno de verificação e, em seguida, corrija a causa real – instale a CA, atualizeca-certificatesou atenda a cadeia completa. Nunca desative a verificação fora de um teste local descartável, pois isso remove a proteção que o erro existe para fornecer.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা