HTTPS protege a comunicação entre cliente e servidor usando TLS. Em uma aplicação Node.js, ele evita que terceiros leiam ou alterem credenciais, cookies, payloads e respostas durante o transporte. Os módulos nativos node:https e node:tls permitem criar servidores, clientes e conexões autenticadas sem bibliotecas externas.
Configurar HTTPS não se resume a carregar um certificado. É necessário validar cadeias de confiança, escolher protocolos modernos, renovar certificados, aplicar timeouts e decidir onde o TLS termina. Em muitas arquiteturas, um proxy ou load balancer recebe a conexão segura e encaminha tráfego para o Node.js.
Neste guia, você aprenderá a criar servidor HTTPS, configurar certificados, usar SNI, validar clientes, implementar mTLS, fazer requisições seguras e organizar rotação e observabilidade.
HTTPS e TLS: qual é a diferença?
TLS é o protocolo que autentica participantes e cria um canal criptografado. HTTPS é HTTP transportado sobre TLS. A conexão começa com um handshake que negocia versão, algoritmo e chaves, além de validar o certificado apresentado pelo servidor.
A documentação oficial de HTTPS e a documentação oficial de TLS detalham opções e eventos.
Para revisar servidores, consulte o que é Node.js e como criar uma API com Node.js.
Criando um servidor HTTPS
const https = require('node:https');
const fs = require('node:fs');
const server = https.createServer({
key: fs.readFileSync('./certs/private-key.pem'),
cert: fs.readFileSync('./certs/certificate.pem')
}, (req, res) => {
res.writeHead(200, {
'content-type': 'application/json'
});
res.end(JSON.stringify({ secure: true }));
});
server.listen(443);Leituras síncronas podem ser aceitáveis durante a inicialização, antes de o servidor aceitar requisições. Durante o atendimento, prefira APIs assíncronas para não bloquear o event loop.
Certificado e chave privada
O certificado contém a chave pública e informações sobre o domínio. A chave privada prova que o servidor controla o certificado e nunca deve ser exposta. A cadeia intermediária também pode precisar ser enviada:
const options = {
key: fs.readFileSync('./certs/key.pem'),
cert: fs.readFileSync('./certs/cert.pem'),
ca: fs.readFileSync('./certs/chain.pem')
};Proteja a chave com permissões restritas ou serviço de segredos. Não a inclua em Git, imagem de contêiner ou logs.
Certificados locais
Em desenvolvimento, use uma autoridade local confiável ou ferramenta que instale um certificado de teste. Desativar validação globalmente ensina o código a aceitar ataques intermediários e pode chegar acidentalmente à produção.
Fazendo uma requisição HTTPS
const https = require('node:https');
const request = https.get(
'https://api.example.com/status',
response => {
const chunks = [];
response.on('data', chunk => chunks.push(chunk));
response.on('end', () => {
console.log(Buffer.concat(chunks).toString('utf8'));
});
}
);
request.on('error', console.error);Para respostas grandes, processe por stream. Veja Streams no Node.js.
Não desative rejectUnauthorized
https.get(url, {
rejectUnauthorized: false
});Essa opção aceita qualquer certificado e elimina a autenticação do servidor. Use apenas em diagnóstico local controlado. Em produção, forneça a CA correta ou corrija a cadeia.
Autoridade certificadora privada
const agent = new https.Agent({
ca: fs.readFileSync('./certs/internal-ca.pem'),
keepAlive: true
});
https.get('https://internal.example', { agent }, response => {
// consumir resposta
});Ao definir ca, confirme se você deseja substituir ou complementar as autoridades padrão.
Reutilizando conexões
Um https.Agent com keep-alive reduz handshakes e latência:
const agent = new https.Agent({
keepAlive: true,
maxSockets: 100,
maxFreeSockets: 20,
timeout: 30_000
});Limite sockets para evitar sobrecarga e feche o agent durante o desligamento.
Timeouts
const req = https.request(options, response => {
// processar resposta
});
req.setTimeout(5000, () => {
req.destroy(new Error('Tempo limite excedido'));
});Timeout de conexão, headers e corpo podem precisar de políticas diferentes. Combine com AbortController no Node.js.
SNI e vários domínios
Server Name Indication permite selecionar certificado conforme o hostname solicitado:
const tls = require('node:tls');
const contexts = {
'api.example.com': tls.createSecureContext({ key, cert }),
'admin.example.com': tls.createSecureContext({
key: adminKey,
cert: adminCert
})
};
const server = https.createServer({
SNICallback(servername, callback) {
callback(null, contexts[servername]);
}
});Valide o hostname e tenha um contexto padrão seguro.
mTLS
No TLS mútuo, o cliente também apresenta certificado. Isso é útil em integrações internas, parceiros e dispositivos:
const server = https.createServer({
key,
cert,
ca: clientCa,
requestCert: true,
rejectUnauthorized: true
}, (req, res) => {
const certificate = req.socket.getPeerCertificate();
res.end(JSON.stringify({ subject: certificate.subject }));
});Não autorize apenas porque o certificado é válido. Verifique identidade, emissor, uso de chave, revogação e permissões do serviço.
Cliente mTLS
const agent = new https.Agent({
key: clientKey,
cert: clientCert,
ca: serverCa,
keepAlive: true
});Distribuição e rotação de certificados de cliente precisam de inventário e automação.
Versões e cifras
Prefira TLS 1.2 ou 1.3, conforme requisitos do ambiente:
const server = https.createServer({
key,
cert,
minVersion: 'TLSv1.2'
});Evite listas manuais de cifras sem necessidade. Atualize Node.js e OpenSSL para receber correções e padrões modernos.
Proxy reverso
Quando Nginx, CDN ou load balancer termina TLS, o Node.js pode receber HTTP interno. Proteja esse trecho em redes não confiáveis e configure corretamente cabeçalhos de proxy. Não aceite X-Forwarded-Proto de qualquer origem.
Para HTTP/2, veja HTTP/2 no Node.js.
HSTS
O cabeçalho Strict-Transport-Security instrui o navegador a usar HTTPS:
res.setHeader(
'strict-transport-security',
'max-age=31536000; includeSubDomains'
);Ative somente quando todos os subdomínios estiverem preparados. Uma configuração incorreta pode bloquear acesso HTTP necessário.
Rotação de certificados
Automatize emissão e renovação. Monitore data de expiração e teste a cadeia. Em serviços que carregam arquivos apenas na inicialização, reinicie de forma gradual após a renovação. Algumas arquiteturas permitem trocar o contexto seguro sem interromper conexões existentes.
Encerramento gradual
Pare novas conexões, aguarde requisições e destrua sockets remanescentes após um limite. Acompanhe agents e conexões keep-alive para o processo não permanecer aberto.
Observabilidade
Monitore falhas de handshake, versão negociada, expiração, tempo de conexão e erros como CERT_HAS_EXPIRED ou UNABLE_TO_VERIFY_LEAF_SIGNATURE. Não registre chaves privadas nem certificados completos de clientes sem necessidade.
Testando
Teste certificado válido, expirado, hostname incorreto, CA privada, cliente sem certificado, rotação e fallback. Use ferramentas como OpenSSL para inspecionar a cadeia e ALPN, mas valide também com o cliente real.
Erros comuns
- Desativar validação de certificado em produção.
- Guardar chave privada no repositório.
- Esquecer certificados intermediários.
- Não definir timeout e limite de sockets.
- Autorizar cliente mTLS apenas pelo CN.
- Confiar em cabeçalhos de proxy não validados.
- Renovar certificado sem recarregar o serviço.
- Permitir versões antigas de TLS.
Boas práticas
- Use TLS 1.2 ou superior.
- Automatize emissão, renovação e alerta de expiração.
- Proteja chaves com controle de acesso.
- Reutilize conexões com limites.
- Defina timeouts em servidor e cliente.
- Valide cadeia, hostname e finalidade.
- Planeje rotação de mTLS.
- Teste através do proxy real.
- Implemente encerramento gradual.
- Mantenha Node.js atualizado.
Conclusão
HTTPS e TLS no Node.js protegem dados em trânsito e autenticam serviços. Os módulos nativos permitem criar servidores seguros, clientes com CA privada e comunicação mTLS.
A proteção depende da operação contínua: validar certificados, limitar conexões, renovar chaves e monitorar falhas. Com configuração moderna e automação, o TLS se torna uma camada previsível da arquitetura, não uma tarefa manual próxima da expiração.




