mTLS no Node.js usa certificados nos dois lados da conexão TLS. O servidor comprova sua identidade ao cliente e também exige que o cliente apresente um certificado confiável. O resultado é autenticação forte entre serviços, dispositivos ou parceiros.
mTLS não substitui autorização. O certificado identifica uma entidade técnica; a aplicação ainda precisa decidir quais recursos essa identidade pode acessar.
TLS comum e mTLS
No HTTPS tradicional, somente o servidor apresenta certificado. Em mTLS, o servidor solicita certificado do cliente e valida a cadeia contra uma autoridade certificadora confiável.
Servidor HTTPS com mTLS
import https from 'node:https';
import fs from 'node:fs';
const server = https.createServer({
key: fs.readFileSync('/run/secrets/server.key'),
cert: fs.readFileSync('/run/secrets/server.crt'),
ca: fs.readFileSync('/run/secrets/client-ca.crt'),
requestCert: true,
rejectUnauthorized: true,
minVersion: 'TLSv1.2'
}, app);requestCert solicita o certificado e rejectUnauthorized bloqueia clientes não confiáveis.
Cliente HTTPS
const agent = new https.Agent({
cert: fs.readFileSync('/run/secrets/client.crt'),
key: fs.readFileSync('/run/secrets/client.key'),
ca: fs.readFileSync('/run/secrets/server-ca.crt'),
minVersion: 'TLSv1.2'
});Com APIs modernas, use um dispatcher ou cliente que aceite configuração TLS equivalente. Não desative validação do servidor.
Lendo a identidade do cliente
const certificate = req.socket.getPeerCertificate();
if (!req.socket.authorized) {
return res.status(401).end();
}
const subject = certificate.subject;
const san = certificate.subjectaltname;Prefira Subject Alternative Name a Common Name. Defina um formato de identidade estável, como URI SAN.
URI SAN e identidade de serviço
URI:spiffe://example.internal/ns/payments/sa/apiUma URI estruturada permite mapear ambiente, namespace e service account. Valide a string completa ou uma política explícita, não apenas um trecho.
Autorização
const permissions = servicePolicy.get(identity);
if (!permissions?.includes('invoices.read')) {
return res.status(403).end();
}Separe autenticação TLS de autorização de aplicação. Certificados diferentes podem ter escopos distintos.
gRPC com mTLS
const serverCredentials = grpc.ServerCredentials.createSsl(
clientCa,
[{ private_key: serverKey, cert_chain: serverCert }],
true
);O último argumento exige certificado do cliente. No cliente:
const credentials = grpc.credentials.createSsl(
serverCa,
clientKey,
clientCert
);Consulte gRPC no Node.js.
Certificados curtos
Prefira certificados de curta duração emitidos automaticamente. Isso reduz a janela de comprometimento e torna rotação uma operação normal.
Rotação
A aplicação pode precisar recarregar certificados sem indisponibilidade. Uma estratégia é criar novo contexto seguro e substituir para novas conexões, mantendo conexões antigas até drenarem.
Teste rotação de CA com sobreposição: confie temporariamente na CA antiga e nova, emita novos certificados e depois remova a antiga.
Armazenamento de chaves
Proteja chaves privadas com permissões restritas, volumes de secrets ou agentes de identidade. Não inclua chaves em imagem Docker, repositório ou variável registrada em logs.
Passphrase
Chaves criptografadas exigem passphrase no startup. Em servidores automatizados, o segredo ainda precisa ser entregue com segurança. Avalie KMS, HSM ou agente local.
Revogação
CRL e OCSP podem ser usados, mas possuem desafios operacionais. Certificados curtos reduzem dependência de revogação imediata. Para incidentes críticos, remova a identidade da autorização além de revogar o certificado.
Proxy ou service mesh
Um proxy pode terminar mTLS e encaminhar identidade em header. Confie nesse header somente quando a aplicação aceita conexões exclusivamente do proxy e remove qualquer valor enviado externamente.
End-to-end versus hop-by-hop
Se o proxy termina TLS, a conexão até a aplicação é outro hop. Avalie se precisa de TLS interno também. Para requisitos fortes, preserve identidade de forma autenticada.
SNI e hostname
O cliente deve validar hostname do servidor. Não configure rejectUnauthorized: false. Em ambientes internos, emita certificado com SAN correspondente ao nome de serviço usado.
ALPN
HTTP/2 e gRPC negociam protocolo via ALPN. Certifique-se de que proxies e configuração TLS suportam o protocolo esperado.
Timeout do handshake
Handshakes consomem CPU e sockets. Defina timeouts e limites de conexão. Reutilize conexões com keep-alive, equilibrando rotação e consumo.
Performance
mTLS adiciona custo principalmente no handshake. Sessões reutilizadas e conexões persistentes reduzem impacto. Meça taxa de handshakes, latência e erros de certificado.
Observabilidade
Registre:
- identidade técnica normalizada;
- issuer e serial de forma segura;
- data de expiração;
- versão TLS e cipher;
- falhas de cadeia;
- certificados prestes a expirar;
- handshake e conexões ativas.
Não registre certificado completo nem chave privada.
Alertas de expiração
Monitore dias restantes e falhas de renovação. Um certificado expirado pode derrubar toda comunicação entre serviços.
Ambientes
Use CAs e trust domains separados por ambiente. Um certificado de desenvolvimento não deve autenticar em produção.
Testes
- cliente válido;
- sem certificado;
- CA desconhecida;
- certificado expirado;
- SAN não autorizado;
- hostname incorreto;
- rotação de leaf e CA;
- proxy tentando forjar header;
- gRPC com streaming;
- certificado revogado na política.
Erros comuns
- usar mTLS sem autorização;
- validar apenas Common Name;
- certificados de anos;
- chave na imagem;
- desativar validação do servidor;
- confiar em header externo;
- não testar rotação;
- uma CA compartilhada entre todos os ambientes;
- sem alerta de expiração.
Conclusão
mTLS no Node.js fornece autenticação criptográfica de cliente e servidor. É especialmente útil para comunicação service-to-service e dispositivos gerenciados.
Use identidades em SAN, certificados curtos, rotação automatizada e autorização separada. Proteja chaves e teste falhas de expiração e CA antes de depender do mecanismo em produção.
Consulte a documentação TLS do Node.js e a documentação HTTPS do Node.js.


