Objetivos de aprendizado
Depois de ler este artigo, você vai conseguir:
- Identificar a causa pela mensagem de erro do navegador, do curl, do Node.js ou do Python
- Diagnosticar certificado vencido, domínio errado e cadeia incompleta com openssl
- Corrigir o problema sem desativar a verificação de certificado
Você abre o seu site e o navegador mostra uma tela vermelha ou o aviso "Não seguro". Ou o seu bot, a sua API ou um curl quebra com certificate has expired. Todos esses casos têm a mesma raiz: na hora de montar a conexão TLS, o cliente recebeu um certificado e não conseguiu confiar nele.
A boa notícia é que são poucas causas, e dá para achar a certa em um minuto com openssl. Este guia vai da mensagem de erro até a correção, sem pedir para você desligar a verificação. Se quiser entender o que o certificado faz, veja o que é SSL/TLS.
Como ler a mensagem de erro?#
A mensagem já aponta a causa. Chrome e navegadores baseados nele mostram um código NET::ERR_...:
NET::ERR_CERT_DATE_INVALID # venceu, ou o relógio do dispositivo está errado
NET::ERR_CERT_COMMON_NAME_INVALID # o certificado não cobre este domínio
NET::ERR_CERT_AUTHORITY_INVALID # emissor desconhecido, autoassinado ou cadeia incompleta
ERR_SSL_VERSION_OR_CIPHER_MISMATCH # handshake: sem versão de TLS ou cifra em comum
ERR_SSL_PROTOCOL_ERROR # handshake: o servidor não falou TLS direitoFora do navegador, os nomes vêm do OpenSSL. No Node.js, o erro traz err.code:
CERT_HAS_EXPIRED # venceu
CERT_NOT_YET_VALID # data de início no futuro
ERR_TLS_CERT_ALTNAME_INVALID # nome do domínio não bate
UNABLE_TO_VERIFY_LEAF_SIGNATURE # cadeia incompleta
DEPTH_ZERO_SELF_SIGNED_CERT # autoassinado
SELF_SIGNED_CERT_IN_CHAIN # autoassinado dentro da cadeiaO curl responde com curl: (60) SSL certificate problem: unable to get local issuer certificate, e o Python com ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]. Esses dois são genéricos: dizem que a verificação falhou, e a causa vem do texto que segue ou do diagnóstico abaixo.
Como diagnosticar com openssl?#
Um comando mostra datas, emissor e nomes cobertos:
echo | openssl s_client -connect exemplo.com:443 -servername exemplo.com 2>/dev/null \
| openssl x509 -noout -dates -issuer -subject -ext subjectAltNameLeia a saída assim:
notAfterno passado: o certificado venceu.subjectAltNamesem o seu domínio: o certificado é de outro nome.issuerigual aosubject: autoassinado.
Para ver a cadeia e o veredito da verificação, rode o s_client sem filtros e procure Verify return code. O valor 0 (ok) indica sucesso. Qualquer outro traz o motivo, como 20 (unable to get local issuer certificate).
O argumento -servername importa: muitos servidores hospedam vários domínios no mesmo IP e escolhem o certificado pelo nome enviado na extensão SNI. Sem ele, você pode receber o certificado errado e achar que o problema é outro.
Por que o certificado venceu?#
É a causa número um. Certificados do Let's Encrypt têm validade curta, e a renovação automática falha em silêncio quando o timer é desativado, a porta 80 passa a ser usada por outro serviço ou a credencial da API de DNS expira. O Let's Encrypt vem encurtando esse prazo em etapas, então a renovação manual deixa de ser viável.
Correção:
- Rode a renovação e leia o erro:
sudo certbot renew --dry-run. - Corrija a causa (porta 80 liberada, DNS apontando para o servidor certo, credencial renovada).
- Recarregue o servidor web, porque muitos só leem o certificado na inicialização:
sudo systemctl reload nginx. - Confirme com o comando
opensslacima.
Detalhes do processo em como funciona o Let's Encrypt. Antes de culpar o servidor, veja a data do seu computador ou celular: relógio errado gera ERR_CERT_DATE_INVALID mesmo com certificado válido.
O que fazer quando o domínio não bate?#
Um certificado vale para uma lista de nomes. exemplo.com não cobre www.exemplo.com, a menos que ambos estejam na lista, e um certificado *.exemplo.com cobre api.exemplo.com, mas não exemplo.com nem a.b.exemplo.com. Causas frequentes:
- O domínio aponta para um servidor que tem o certificado de outro site.
- O DNS ainda aponta para o IP antigo (veja propagação de DNS).
- Você emitiu o certificado só para o domínio raiz e esqueceu o
www.
Corrija emitindo o certificado com todos os nomes usados e conferindo para onde o domínio resolve (dig +short exemplo.com). O passo a passo está em como apontar um domínio para sua aplicação.
E se a cadeia estiver incompleta?#
O servidor precisa enviar o certificado do site mais os intermediários. Navegadores às vezes completam a cadeia sozinhos, mas curl, Node.js e Python não, e é por isso que o site abre no Chrome e a sua API falha com UNABLE_TO_VERIFY_LEAF_SIGNATURE ou unable to get local issuer certificate.
A correção é servir o arquivo com a cadeia completa. Com o Certbot, é o fullchain.pem, não o cert.pem:
ssl_certificate /etc/letsencrypt/live/exemplo.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/exemplo.com/privkey.pem;Se o erro aparece só na sua máquina, com um certificado de uma CA privada (rede corporativa, proxy de inspeção, ambiente interno), confie nessa CA em vez de desligar a verificação:
curl --cacert ./minha-ca.pem https://interno.exemplo.com
NODE_EXTRA_CA_CERTS=./minha-ca.pem node app.jsNo Node.js, rejectUnauthorized vem como true por padrão, e false remove toda a proteção contra interceptação. Para uma CA própria, passe-a na opção ca.
Por que aparece "Não seguro" com HTTPS ativo?#
Se o certificado está certo e o cadeado ainda não aparece, o suspeito é conteúdo misto: a página veio por HTTPS, mas carrega algo por http://. Segundo o MDN, navegadores atualizam imagens, áudio e vídeo para HTTPS por conta própria, mas bloqueiam scripts, CSS, iframes e chamadas fetch. O resultado é uma página quebrada ou com aviso.
Abra o console do navegador (F12): cada recurso afetado aparece com a URL. Troque http:// por https:// ou por caminhos relativos. Como atalho, o cabeçalho Content-Security-Policy: upgrade-insecure-requests pede ao navegador que atualize todas as requisições, mas só funciona se o outro lado também atende por HTTPS.
E os erros de handshake?#
Se o erro é ERR_SSL_VERSION_OR_CIPHER_MISMATCH ou ERR_SSL_PROTOCOL_ERROR, a negociação falhou antes da verificação do certificado. Cheque:
- Porta ou protocolo errado: você está falando HTTPS com uma porta que atende HTTP puro (ou o contrário).
- Versão de TLS antiga: servidores só com TLS 1.0 ou 1.1, já descontinuados, são recusados por clientes atuais. Use TLS 1.2 ou 1.3.
- Servidor sem certificado configurado para aquele nome ou porta.
Teste com openssl s_client -connect exemplo.com:443 -tls1_2 e -tls1_3 para ver qual versão o servidor aceita.
Como fazer isso na Square Cloud#
Na Square Cloud, várias dessas causas somem porque o TLS é automático: o certificado DV é emitido e renovado sozinho, e o HTTP é redirecionado para HTTPS. Toda aplicação web ganha um subdomínio *.squareweb.app com HTTPS, em todos os planos.
Para domínio próprio, a partir do plano Standard, você cria no seu registrador os registros DNS mostrados no painel e acompanha ali o status da validação em tempo real. Se a validação não conclui, confira se os registros criados são exatamente os que o painel mostra. O TLS do domínio também é automático, e há suporte a domínios com acento (Punycode) e purge de cache. O domínio continua registrado em seu nome no seu registrador.
Veja a página de domínios para o passo a passo.
Rede
Domínio próprio, TLS automático e CDN global para o seu app
Perguntas frequentes
Por que o navegador diz 'Não seguro' se o site tem HTTPS?
Duas causas comuns: o certificado tem problema (vencido, domínio errado, emissor desconhecido) ou a página HTTPS carrega algum recurso por HTTP, o chamado conteúdo misto. O console do navegador mostra qual dos dois é.
Posso desativar a verificação de certificado para o erro sumir?
Só em teste local descartável. Com rejectUnauthorized: false no Node.js ou curl -k, qualquer pessoa no caminho pode se passar pelo servidor. Em produção, corrija o certificado ou instale a CA correta.
O que significa NET::ERR_CERT_DATE_INVALID?
O certificado venceu ou ainda não é válido. Se o certificado do servidor está dentro do prazo, confira o relógio do dispositivo: data errada gera o mesmo erro.
Qual a diferença entre erro de certificado e erro de handshake?
No erro de certificado, o handshake chegou até a verificação e o certificado foi recusado. No erro de handshake, a negociação falha antes: versão de TLS ou cifras sem ponto em comum, ou o servidor nem responde em TLS naquela porta.
Mais em Rede e domínios
Ver todos os 27 artigos- O que é load balancer (balanceamento de carga)Load balancer é o componente que distribui requisições entre vários servidores. Veja como funciona, os algoritmos, as camadas 4 e 7 e um exemplo com nginx.
- Registros DNS: A, CNAME, MX e TXT explicadosRegistros DNS são as instruções de uma zona que dizem para onde um nome aponta. Entenda A, AAAA, CNAME, MX, TXT, NS e CAA com exemplos e comandos dig.
- Como apontar um domínio para sua hospedagemPara apontar um domínio para sua hospedagem, crie um registro CNAME (ou A) no DNS do seu registrador. Veja o passo a passo, como testar e os erros comuns.
- Cabeçalho Cache-Control: quanto tempo o navegador e a CDN guardam um arquivoCache-Control é o cabeçalho HTTP que define quanto tempo navegador e CDN guardam uma resposta. Veja max-age, no-cache, immutable e receitas por tipo de arquivo.