Pular para o conteúdo
ecdsa.com

Certificados autoassinados vs assinados por CA: qual usar

Os dois criptografam igualmente bem. A diferença está em quem atesta a chave, como os clientes passam a confiar nela e o que quebra quando você a rotaciona.

Autoassinado vs assinado por CA é uma questão de quem atesta o vínculo entre uma chave pública e um nome. Um certificado autoassinado é assinado com a própria chave, então só prova que o portador dele tem essa chave; um cliente só confia nele se tiver sido instruído a confiar exatamente nesse certificado. Um certificado assinado por CA é assinado por uma autoridade certificadora cuja raiz o cliente já considera confiável: uma CA pública, para a internet, ou uma CA privada que você mesmo opera e distribui.

Visão geral

AutoassinadoCA privadaCA pública
Quem assina o certificado folhaA própria chave do certificado folhaSua raiz ou intermediáriaUma CA presente nos root stores dos navegadores e dos sistemas operacionais
Como os clientes passam a confiar neleCada cliente fixa ou instala exatamente este certificadoInstalação de uma raiz (MDM, gerenciamento de configuração, imagem de contêiner)Já é confiável por padrão
Rotação do certificado folhaTodos os clientes precisam ser atualizadosTransparente para os clientesTransparente para os clientes
RevogaçãoNenhuma; é preciso removê-lo de cada clienteSua própria CRL, OCSP ou vida útil curtaCRLs publicadas pela CA
Nomes que pode conterQualquer umQualquer um dentro das restrições da raizApenas nomes de domínio públicos e IPs públicos
Limites de vida útilNenhum imposto pelos navegadores; as plataformas Apple limitam a 825 dias os certificados TLS emitidos desde julho de 2019O mesmo limite de 825 dias nas plataformas Apple200 dias hoje, 47 dias a partir de março de 2029
Certificate TransparencyNão registradoNão registradoRegistrado publicamente, incluindo cada nome de host
Custo e esforçoNenhum no início; alto a cada rotaçãoOperar a CA e proteger a chave delaGratuito com ACME; exige validação por DNS ou HTTP
Ferramentas típicasopenssl req -x509, mkcert para desenvolvimento localstep-ca, HashiCorp Vault PKI, CAs privadas de nuvem, cert-managerLet’s Encrypt e outras CAs ACME

Como os clientes decidem confiar em um certificado

A validação de caminho (RFC 5280 §6) monta uma cadeia que vai do certificado do servidor até uma âncora de confiança no root store do cliente e, no caminho, verifica cada assinatura, o período de validade e as extensões Basic Constraints, Key Usage e Name Constraints. Um certificado autoassinado tem o mesmo emissor e o mesmo titular e é assinado pela própria chave, então a única cadeia possível é o próprio certificado. Ele só é validado se esse certificado for, ele mesmo, uma âncora de confiança para o cliente, e é exatamente isso que significa “fixar” ou “instalar” um certificado autoassinado.

Um certificado folha assinado por CA é assinado por uma CA intermediária, que por sua vez se encadeia a uma CA raiz. O cliente nunca precisa conhecer o certificado folha de antemão; ele só precisa da raiz. É essa indireção que torna possíveis a rotação, a revogação e a automação.

O script abaixo, executado com o OpenSSL 3.6.5, cria um certificado autoassinado, uma raiz privada limitada a nomes sob .internal e dois certificados folha assinados por essa raiz.

Certificado autoassinado, CA privada e Name Constraints
#!/bin/sh
dir=$(mktemp -d)
cd "$dir" || exit 1
P256="-newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc"

# 1. Self-signed server certificate
openssl req -x509 $P256 -keyout self.key -out self.pem -days 30 \
  -subj "/CN=dev.internal" \
  -addext "subjectAltName=DNS:dev.internal,IP:127.0.0.1" \
  -addext "basicConstraints=critical,CA:FALSE" 2>/dev/null
openssl verify self.pem
openssl verify -CAfile self.pem self.pem

# 2. Private root CA limited to .internal names
openssl req -x509 $P256 -keyout ca.key -out ca.pem -days 3650 \
  -subj "/CN=Example Internal Root" \
  -addext "keyUsage=critical,keyCertSign,cRLSign" \
  -addext "nameConstraints=critical,permitted;DNS:.internal" 2>/dev/null

# 3. Two server certificates signed by that CA
for name in api.internal www.example.com; do
  openssl req -x509 $P256 -CA ca.pem -CAkey ca.key -keyout "$name.key" \
    -out "$name.pem" -days 90 -subj "/CN=$name" \
    -addext "subjectAltName=DNS:$name" \
    -addext "basicConstraints=critical,CA:FALSE" \
    -addext "extendedKeyUsage=serverAuth" 2>/dev/null
done
openssl verify api.internal.pem
openssl verify -CAfile ca.pem api.internal.pem
openssl verify -CAfile ca.pem www.example.com.pem
cd / && rm -rf "$dir"
Saída
CN=dev.internal
error 18 at 0 depth lookup: self-signed certificate
error self.pem: verification failed
self.pem: OK
CN=api.internal
error 20 at 0 depth lookup: unable to get local issuer certificate
error api.internal.pem: verification failed
api.internal.pem: OK
CN=www.example.com
error 47 at 0 depth lookup: permitted subtree violation
error www.example.com.pem: verification failed

O certificado autoassinado só passa na verificação quando é informado como sua própria âncora de confiança. O certificado folha da CA privada passa na verificação assim que a raiz é considerada confiável, e a extensão Name Constraints da raiz impede que ela ateste www.example.com, o que limita o estrago se a chave da CA chegar a ser usada indevidamente. Observe que o openssl req -x509 marca os certificados como CA por padrão, por meio do arquivo de configuração; o CA:FALSE explícito impede que o certificado de servidor autoassinado possa ser usado como emissor.

O que os clientes dizem quando não confiam no certificado

Apontamos cinco clientes para um servidor local que apresentava cada um dos certificados, sem adicionar nada aos trust stores deles (20 de outubro de 2026, macOS).

ClienteCertificado autoassinadoCertificado folha de uma CA privada não confiável
Node.js 26.10DEPTH_ZERO_SELF_SIGNED_CERTUNABLE_TO_VERIFY_LEAF_SIGNATURE
Python 3.14 (OpenSSL 3.6.5)certificate verify failed: self-signed certificatecertificate verify failed: unable to get local issuer certificate
Go 1.25 (verificador do macOS)x509: certificate signed by unknown authorityx509: “localhost” certificate is not trusted
curl 8.7.1 (LibreSSL)(60) SSL certificate problem: self signed certificate(60) SSL certificate problem: unable to get local issuer certificate
OpenSSL 3.6.5 s_clientVerify return code: 18 (self-signed certificate)Verify return code: 20 (unable to get local issuer certificate)

Os navegadores mostram NET::ERR_CERT_AUTHORITY_INVALID (Chrome) ou MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT (Firefox). A solução nunca é desativar a verificação (NODE_TLS_REJECT_UNAUTHORIZED=0, verify=False, InsecureSkipVerify, curl -k): isso elimina a autenticação de todas as conexões que o processo abre. Em vez disso, forneça ao cliente o certificado ou a raiz em que ele deve confiar (ca: no Node.js, cafile= no Python, um pool RootCAs personalizado no Go, --cacert no curl) ou instale a raiz no trust store do sistema operacional. Um certificado sem um nome DNS na extensão Subject Alternative Name falha de outro jeito: o Chrome deixou de comparar o Common Name na versão 58 (2017), e as plataformas Apple, a partir do iOS 13 e do macOS 10.15.

O meio-termo: uma CA privada

Uma CA privada mantém a principal vantagem da autoassinatura (nenhuma parte externa, qualquer nome interno, nada publicado em logs públicos) e elimina seu principal custo (redistribuir a confiança a cada rotação). Regras práticas:

  • Mantenha a raiz offline e emita a partir de uma intermediária; uma intermediária comprometida pode ser substituída sem mexer em cada cliente.
  • Restrinja os nomes às suas zonas internas, como na demonstração, e mantenha o pathlen e o Key Usage tão restritos quanto possível.
  • Automatize os certificados folha: step-ca, Vault PKI e cert-manager podem emitir via ACME ou pelas próprias APIs, de modo que os certificados folha podem durar horas ou dias e a revogação se torna desnecessária.
  • Respeite as regras dos clientes mesmo assim: as plataformas Apple exigem um nome DNS no SAN, o Extended Key Usage serverAuth e no máximo 825 dias de validade para certificados TLS emitidos desde 1º de julho de 2019, também com raízes privadas; o limite de 398 dias vale apenas para raízes publicamente confiáveis.
  • Planeje a distribuição da raiz: os trust stores do sistema operacional, os keystores Java, as imagens de contêiner, os navegadores com trust store próprio (Firefox) e os softwares que trazem o próprio bundle (o pacote certifi por trás do requests do Python e o Node.js, que usa o bundle Mozilla embutido, a menos que seja iniciado com --use-system-ca) precisam, cada um, receber a raiz.

Onde uma CA pública não ajuda

As CAs públicas não podem emitir certificados que contenham nomes internos ou endereços IP reservados (Baseline Requirements §4.2.2). Por isso, nomes como printer.local, hosts de rótulo único, 10.0.0.5 ou qualquer coisa sob .internal, que a ICANN reservou permanentemente para uso privado em 29 de julho de 2024, só podem vir de uma CA privada ou de um certificado autoassinado. Hosts internos com nomes públicos (por exemplo, db.corp.example.com) podem obter certificados públicos pelo desafio DNS-01 sem ficar acessíveis pela internet, mas cada nome passa a aparecer nos logs públicos de Certificate Transparency, o que revela sua topologia interna a qualquer pessoa que faça buscas neles.

Quando escolher cada um

  • Sites públicos, APIs e servidores de e-mail: CA pública com ACME.
  • Serviços internos, malhas de serviço, mTLS entre cargas de trabalho: CA privada com certificados folha de curta duração.
  • Desenvolvimento local: uma CA local de desenvolvimento, como o mkcert, que instala a raiz dela nos seus próprios trust stores, em vez de certificados autoassinados que cada ferramenta rejeita de um jeito diferente.
  • Dispositivos e equipamentos na primeira inicialização: um certificado autoassinado cuja impressão digital o usuário ou o sistema de provisionamento verifica uma vez, seguido do registro em uma CA privada.
  • Fixtures de teste: certificados autoassinados gerados pelo próprio teste e passados explicitamente ao cliente testado.
  • Parceiros e integrações B2B via mTLS: uma CA privada dedicada a essa relação, nunca sua raiz interna geral.

Notas de migração

  1. Faça um inventário dos certificados autoassinados em uso: varra os endpoints internos e colete os certificados que os clientes fixam; o decodificador de certificados mostra o emissor, os SANs e a expiração.
  2. Monte uma CA privada com uma raiz offline e uma intermediária emissora, restrita aos seus domínios internos; gere as solicitações com o gerador de CSR.
  3. Distribua a raiz antes de trocar qualquer servidor e depois substitua os certificados folha serviço por serviço; o construtor de cadeia de certificados confirma que cada servidor envia o intermediário.
  4. Remova as soluções de contorno inseguras (-k, verify=False, InsecureSkipVerify) quando os clientes passarem a confiar na raiz e faça uma busca na base de código para que elas não voltem.
  5. Leve os nomes voltados ao público para uma CA pública com ACME e mantenha a fixação (se houver) nas chaves, e não nos certificados; o gerador de pins SPKI calcula pins que sobrevivem à renovação com a mesma chave.

Referências

Todas as comparações