Implementar mTLS no Node.js permite que servidor e cliente apresentem certificados durante o handshake TLS. No HTTPS tradicional, o cliente valida o certificado do servidor. No mutual TLS, o servidor também valida o certificado do cliente, criando autenticação criptográfica nos dois sentidos.
mTLS é útil em comunicação entre serviços, integrações B2B, APIs administrativas e ambientes com requisitos de identidade de workload. A tecnologia não substitui autorização: um certificado válido identifica o cliente, mas a aplicação ainda precisa decidir quais rotas, tenants e ações estão permitidos.
Neste guia, você aprenderá a criar um servidor HTTPS com certificado cliente obrigatório, configurar o cliente, validar CA, ler o certificado, mapear identidades, rotacionar chaves, usar proxies, revogar acesso, monitorar e testar o fluxo.
O que é mTLS?
mTLS significa Mutual Transport Layer Security. O módulo nativo node:tls fornece a implementação TLS do Node.js sobre OpenSSL. A RFC 8446 define TLS 1.3.
TLS comum versus mTLS
- TLS comum: cliente valida o servidor.
- mTLS: cliente valida o servidor e servidor valida o cliente.
O canal fica cifrado nos dois casos. A diferença é a autenticação do cliente por certificado.
Componentes
- CA raiz ou intermediária;
- certificado do servidor;
- chave privada do servidor;
- certificado do cliente;
- chave privada do cliente;
- política de emissão e rotação;
- mapeamento entre certificado e identidade.
Autoridade certificadora
A CA assina certificados confiáveis. Em ambientes internos, use uma PKI própria ou serviço gerenciado. Não compartilhe a chave privada da CA com aplicações.
Certificados autoassinados
Um certificado autoassinado isolado pode funcionar em desenvolvimento, mas não escala bem para rotação e revogação. Prefira uma CA que assine certificados individuais.
Servidor HTTPS com mTLS
import https from 'node:https';
import fs from 'node:fs';
const server = https.createServer({
key: fs.readFileSync('/run/tls/server-key.pem'),
cert: fs.readFileSync('/run/tls/server-cert.pem'),
ca: fs.readFileSync('/run/tls/client-ca.pem'),
requestCert: true,
rejectUnauthorized: true,
minVersion: 'TLSv1.2'
}, app);
server.listen(8443);requestCert solicita o certificado do cliente. rejectUnauthorized rejeita conexões que não passam pela validação da CA.
Não use rejectUnauthorized false
rejectUnauthorized: falseEssa configuração aceita certificados não confiáveis e elimina a principal proteção. Não use como correção para erros de cadeia.
Cliente HTTPS
import https from 'node:https';
import fs from 'node:fs';
const agent = new https.Agent({
key: fs.readFileSync('/run/tls/client-key.pem'),
cert: fs.readFileSync('/run/tls/client-cert.pem'),
ca: fs.readFileSync('/run/tls/server-ca.pem'),
minVersion: 'TLSv1.2',
keepAlive: true
});O cliente envia seu certificado e valida o servidor com a CA configurada.
Fetch com agente
O mecanismo exato depende do cliente HTTP. Bibliotecas como Undici permitem configurar um dispatcher com opções TLS. Confira a documentação da versão usada.
Hostname do servidor
O certificado do servidor precisa conter o hostname em Subject Alternative Name. Não desabilite a validação de hostname.
Certificate Authority
O campo ca deve conter a cadeia confiável apropriada. Não confie em certificados individuais de clientes quando uma CA e política de emissão são mais adequadas.
Lendo o certificado do cliente
app.use((req, res, next) => {
if (!req.socket.authorized) {
return res.status(401).end();
}
const certificate = req.socket.getPeerCertificate();
req.clientCertificate = certificate;
next();
});authorized e authorizationError
authorized indica se a cadeia foi validada. Quando falha, authorizationError ajuda no diagnóstico interno. Não envie detalhes do certificado ao cliente.
Identidade no certificado
Você pode usar Subject Alternative Name, URI, DNS ou outro identificador emitido pela CA. Evite depender apenas de Common Name em desenhos modernos.
URI de workload
spiffe://empresa.local/ns/payments/sa/apiIdentidades URI facilitam mapear workload e ambiente, especialmente com SPIFFE e service mesh.
Mapeando para o cliente
const identity = extractApprovedIdentity(certificate);
const client = await clients.findByCertificateIdentity(identity);
if (!client || client.status !== 'active') {
throw new UnauthorizedError();
}O certificado válido precisa corresponder a um registro ativo.
Autenticação não é autorização
Depois de identificar o cliente, verifique escopos e recursos:
requirePermission(client, 'payments.read');Consulte RBAC no Node.js e ABAC no Node.js.
mTLS e API keys
Uma integração pode combinar certificado com API key. O certificado identifica a máquina ou organização; a chave representa uma credencial adicional com escopos.
Veja API Keys no Node.js.
mTLS e OAuth
Arquiteturas OAuth podem vincular tokens ao certificado, reduzindo uso por quem rouba apenas o token. A configuração é mais complexa e deve seguir o provedor e as especificações adotadas.
Certificado por serviço
Não compartilhe o mesmo certificado entre todos os serviços. Credenciais individuais permitem revogar, auditar e aplicar políticas específicas.
Certificado por ambiente
Desenvolvimento, homologação e produção devem usar CAs ou políticas distintas. Um certificado de teste não deve autenticar produção.
Chave privada
A chave privada é um segredo. Armazene em Secret, KMS, HSM, volume protegido ou identidade de workload.
Consulte Gestão de Segredos no Node.js.
Permissões do arquivo
chmod 600 client-key.pemO processo deve ser o único usuário autorizado a ler a chave.
Passphrase
Chaves podem ser cifradas com passphrase, mas o processo precisa receber essa passphrase. Em serviços automatizados, HSM ou secret mount pode ser mais prático.
Rotação de certificado
- Emitir certificado novo.
- Entregar ao workload.
- Recarregar sem interromper conexões novas.
- Confirmar uso.
- Revogar ou expirar o antigo.
- Auditar.
Sobreposição
Durante a rotação, a CA pode aceitar certificado antigo e novo por um período curto. Isso evita indisponibilidade.
Recarregando contexto
Servidores Node.js podem atualizar o contexto TLS ou reiniciar de forma gradual. Teste o comportamento do framework e do balanceador.
Conexões existentes
Rotacionar certificado afeta novos handshakes. Conexões keep-alive já estabelecidas podem continuar até serem drenadas.
Expiração curta
Certificados de workload com validade curta reduzem a dependência de listas de revogação e limitam o impacto de vazamento.
Renovação automática
Use um agente ou plataforma que renove antes do vencimento. Monitore o prazo e alerte com antecedência.
Revogação
CRL e OCSP podem ser usados conforme a PKI. Em ambientes internos, certificados curtos e remoção da identidade no gateway também são comuns.
Serial number
Registre serial, issuer e fingerprint para auditoria. Não use apenas o subject, que pode ser repetido.
Fingerprint
Pinning por fingerprint facilita um caso pequeno, mas torna rotação difícil. Uma CA com identidade e política geralmente escala melhor.
Proxy reverso
O mTLS pode terminar no Nginx, load balancer ou API Gateway. Nesse caso, o proxy valida o certificado e encaminha uma identidade confiável.
Headers internos
Remova headers fornecidos pelo cliente e defina novos valores somente no proxy:
X-Client-Certificate-Identity
X-Client-Certificate-SerialA aplicação deve aceitar esses headers apenas de proxies autenticados.
mTLS fim a fim
Quando o risco exige, mantenha TLS mútuo entre proxy e serviço, em vez de confiar apenas na rede interna.
API Gateway
Gateways podem centralizar certificados, políticas e rate limiting. Consulte API Gateway no Node.js.
Service mesh
Uma malha pode emitir certificados de workload e aplicar mTLS transparente. Ainda é necessário validar autorização e política de tráfego.
Zero Trust
mTLS fornece identidade de conexão, mas Zero Trust também exige autorização, estado do dispositivo, segmentação, observabilidade e privilégio mínimo.
TLS mínimo
Use versões modernas e evite reduzir o nível de segurança apenas para clientes antigos. A documentação do Node.js recomenda cautela ao alterar suites e níveis padrão.
Ciphers
Os defaults do Node.js refletem práticas atuais. Personalizar suites sem necessidade pode remover proteções. Faça apenas com requisito e teste.
Session resumption
Reuso de sessão reduz custo de handshake. As chaves de ticket são segredos e precisam de rotação e distribuição segura entre instâncias.
Keep-alive
Clientes devem reutilizar conexões para reduzir CPU e latência. Consulte HTTP Agent no Node.js.
Timeouts
Defina timeout de handshake, conexão e resposta. Clientes que abrem sockets sem completar TLS podem consumir recursos.
Rate limiting
Certificado válido não autoriza tráfego ilimitado. Limite por identidade e rota.
Logs
Registre identidade, serial, issuer, protocolo, cipher, rota e resultado. Não registre a chave privada ou certificado completo sem necessidade.
Consulte Logs com Pino no Node.js.
Auditoria
Emissão, renovação, revogação e alterações de CA devem ser auditadas. Veja Logs de Auditoria no Node.js.
Métricas
Monitore handshakes, falhas por CA, certificados expirados, protocolo, latência, conexões reutilizadas e identidades bloqueadas.
Alertas
Alerte sobre certificado perto do vencimento, issuer inesperado, aumento de falhas e uso de identidade revogada.
Teste com OpenSSL
openssl s_client \
-connect localhost:8443 \
-cert client-cert.pem \
-key client-key.pem \
-CAfile server-ca.pemTeste sem certificado
A conexão deve falhar antes da rota protegida.
Teste com CA errada
Um certificado assinado por CA não confiável deve ser rejeitado.
Teste de expiração
Use fixture expirada e confirme o erro. Monitore o código de validação internamente.
Teste de identidade
Um certificado válido para o serviço A não deve acessar permissões do serviço B.
Teste de rotação
Mantenha conexões ativas, instale o certificado novo e confirme que novas conexões usam a nova versão sem downtime.
Teste de proxy
Envie um header de identidade diretamente. O proxy deve removê-lo e a aplicação não deve confiar em origem externa.
Erros comuns
- rejectUnauthorized false: certificados não confiáveis são aceitos.
- Certificado compartilhado: não há identidade individual.
- Common Name sem política: mapeamento fica frágil.
- Chave na imagem: qualquer cópia possui a credencial.
- Sem rotação: certificados expiram ou permanecem vazados.
- Confiar em header externo: identidade é forjada.
- Tratar mTLS como autorização: cliente recebe acesso excessivo.
Boas práticas
- Use CA controlada.
- Exija certificado cliente.
- Mantenha rejectUnauthorized ativo.
- Use identidade estável no SAN.
- Emita certificado por workload.
- Proteja chaves privadas.
- Use validade curta.
- Rotacione automaticamente.
- Autorize por escopo.
- Teste expiração e proxy.
Conclusão
Implementar mTLS no Node.js fornece identidade criptográfica para cliente e servidor durante o handshake. Isso protege integrações e comunicação entre serviços contra clientes sem certificado confiável.
O valor real aparece quando certificados são individuais, curtos e rotacionados, enquanto a aplicação aplica autorização por identidade e escopo. Com PKI, gerenciamento de segredos, observabilidade e testes de renovação, mTLS se torna uma camada forte sem criar certificados permanentes impossíveis de operar.



