Como implementar o pinning de SSL/TLS no Node.js
Nwani Victory
29 de agosto de 2023
0 minutos de leituraComo agentes de ameaça realizam ataques man-in-the-middle (MITM), ter um certificado SSL/TLS já não é motivo suficiente para confiar em uma conexão recebida. Por isso, desenvolvedores estão adotando cada vez mais o pinning de SSL/TLS, também conhecido como pinning de certificados ou de chaves públicas, como uma medida adicional para comprovar a autenticidade e a integridade de uma conexão.
Em uma aplicação Node.js, o pinning de SSL/TLS adiciona uma camada extra de segurança, impedindo que invasores interceptem e alterem a comunicação entre o cliente e o servidor.
Este artigo explica o pinning de certificados e destaca seus benefícios e casos de uso em aplicações Node.js.
Quando e por que usar o pinning de SSL/TLS
O pinning de SSL/TLS é um mecanismo de segurança que ajuda a proteger contra ataques MITM e outros ataques relacionados a certificados. Para isso, garante que um cliente, como uma aplicação Node.js, se conecte apenas a um servidor com um certificado digital previamente verificado. Essa técnica armazena e usa certificados ou chaves públicas específicos em aplicações host para compará-los com a chave pública ou o certificado do servidor. Podemos codificar os certificados ou as chaves públicas diretamente nas aplicações por meio de variáveis de ambiente ou armazená-los externamente em um serviço de cofre de chaves, para ter mais flexibilidade.
O pinning de certificados reduz os riscos de ataques MITM ao considerar maliciosas todas as solicitações sem um certificado fixado correspondente e encerrá-las, mesmo que usem HTTPS. Ele também ajuda a prevenir outras vulnerabilidades relacionadas a certificados, como falsificação ou adulteração de certificados e comprometimento de autoridades certificadoras (CAs).
De acordo com a Pesquisa para Desenvolvedores do Stack Overflow, 47,12% dos desenvolvedores usam Node.js, o que o torna uma tecnologia padrão para aplicações web no lado do servidor. Módulos integrados ao Node.js, como o HTTPS, adicionam uma camada extra de proteção à aplicação ao validar certificados fixados. Uma aplicação Node.js que usa pinning de certificados compara o certificado apresentado durante o handshake TLS com o certificado ou as chaves públicas predefinidos. Se houver divergência, ela encerra a solicitação na camada de transporte.
Um caso de uso do pinning de certificados são as aplicações financeiras em dispositivos móveis. Um ataque MITM contra um dispositivo desse tipo pode ter consequências catastróficas para seu proprietário, já que ele pode transmitir informações pessoais confidenciais, como dados de cartões de crédito ou de contato. Embora versões mais recentes de sistemas operacionais móveis, como o Android Pie, tenham recursos de segurança que permitem às aplicações estabelecer apenas conexões seguras, agentes de ameaça podem lançar ataques de phishing gerando certificados autoassinados para acessar o dispositivo. O pinning de certificados garante que a aplicação não aceite uma conexão maliciosa, mesmo que o dispositivo confie no certificado autoassinado.
Preparação para implementar o pinning de SSL/TLS
Quando um cliente envia uma solicitação de rede a um servidor, a camada de transporte inicia um handshake seguro usando o protocolo SSL/TLS. O servidor apresenta seu certificado digital, que contém a chave pública usada para criptografia e autenticação. Durante o handshake, a aplicação recupera a chave pública do servidor a partir do certificado apresentado.
A aplicação compara a chave pública recuperada com uma cópia pré-configurada ou codificada diretamente. Se as chaves forem iguais, a conexão é considerada segura e a comunicação pode continuar. Se forem diferentes, a aplicação pode encerrar a conexão ou tomar as medidas previstas em sua política de segurança, como emitir um alerta ou se recusar a enviar dados confidenciais.
As CAs têm um papel fundamental no processo de pinning de certificados, pois fornecem os certificados SSL/TLS necessários para estabelecer uma conexão segura. A CA assina o certificado, que é validado pelo navegador em aplicações web ou pela cadeia de confiança do sistema operacional. O pinning de certificados é uma etapa adicional para confirmar que o certificado é confiável.
TLS é um módulo integrado ao Node.js que pode extrair de um host um objeto de certificado com um campo de chave pública. O código abaixo mostra como usar o módulo TLS para fazer uma solicitação a um host e recuperar o certificado em um objeto:
Neste código, o método getPeerCertificate é responsável por extrair o certificado. Também podemos usar o método getPeerX509Certificate para recuperar o certificado do par no formato de um objeto x509Certificate.
Implementando o pinning de SSL/TLS no Node.js
Para usar o pinning de SSL/TLS em uma aplicação Node.js, precisamos especificar a chave ou o certificado nas configurações da solicitação. Em HTTPS, as propriedades ca, cert e key nas opções de https.request ajudam a implementar o pinning de SSL/TLS. Ao fixar um certificado, a propriedade `ca` deve especificar um array com certificados confiáveis codificados em privacy-enhanced mail (PEM) ou certificados de CA. A propriedade key deve especificar um array com as chaves privadas associadas a um certificado de servidor confiável.
Snyk Code é uma ferramenta de teste estático de segurança de aplicações (SAST), desenvolvida para priorizar as necessidades dos desenvolvedores e identificar vulnerabilidades de segurança em uma base de código em tempo real, durante o desenvolvimento. Ela está disponível por meio de comandos de interface de linha de comando (CLI), kits de desenvolvimento de software (SDKs) para pipelines de integração e entrega contínuas (CI/CD), interfaces web, extensões para ambientes de desenvolvimento integrado (IDEs) e editores de código. Em um projeto Node.js, o Snyk Code pode detectar e alertar quando não há suporte a certificados SSL/TLS.
Para identificar a falta de suporte a SSL/TLS, use o comando code test abaixo para analisar a base de código do projeto pelo terminal. O comando snyk ignore --file-path=<file_path> permite ignorar arquivos ou diretórios que não queremos incluir na análise do Snyk, como o diretório node_modules, que contém os pacotes do Node.js:
Embora o pinning de SSL/TLS ofereça benefícios de segurança, uma implementação malfeita e sem tratamento de erros também pode ser desastrosa. Nossas implementações de pinning devem ter um plano de contingência para lidar com situações excepcionais, como a revogação ou o vencimento do certificado fixado. O tratamento de erros evita que a aplicação inteira falhe quando não for possível confirmar um certificado ou uma chave pública. A execução de auditorias pode ajudar a registrar esses casos.
Para começar, crie um diretório chamado snyk-tls e use:
O código abaixo mostra uma impressão digital de chave pública fixada em uma aplicação Node.js, que corresponde à impressão digital da chave pública do certificado para uma solicitação GET criada com o módulo nativo https do Node.js. Se as impressões digitais das chaves públicas não corresponderem, o código cancela a solicitação. Crie um arquivo index.js e adicione o código a seguir para testar:
No código acima, o array PINNED_CERT_FINGERPRINTS é verificado para determinar se a impressão digital do certificado público está entre as impressões permitidas. Se ela não estiver no array, o método destroy encerra a solicitação.
Em produção, devemos armazenar a chave pública ou o certificado em variáveis de ambiente ou em um serviço de cofre de chaves separado. Assim, evitamos expor a chave pública ao enviar o código para um repositório.
Testar e manter o pinning de SSL/TLS
Uma ótima maneira de testar a eficácia de uma implementação de pinning é simular um ataque MITM. Ferramentas como Mitmproxy ou Wireshack permitem criar um ambiente de teste para monitorar, interceptar e encaminhar solicitações de rede para um host de teste.
Para testar a eficácia do nosso pinning de SSL/TLS, precisamos desativar os certificados fixados e lançar um ataque MITM por meio de um proxy para registrar o comportamento de referência da aplicação sem o pinning. Em seguida, repetimos o teste com o pinning ativado para ver se a aplicação consegue detectar o proxy e encerrar a conexão.
Comparar o hash da chave do certificado é outra forma de testar o pinning de SSL/TLS. O hash de um certificado é exclusivo, pois uma função de hash criptográfica converte dados de tamanho arbitrário em valores de tamanho fixo que representam o certificado. Isso faz dele uma opção adequada para validar um certificado. Com o módulo crypto do Node.js, podemos gerar um hash a partir do certificado do host e compará-lo ao hash esperado da chave pública.
Uma terceira forma de testar o pinning de SSL/TLS é usar ferramentas de varredura de rede, como o Nmap, para executar uma varredura de portas SSL. O Nmap oferece o comando ssl-enum-chipers para verificar uma porta SSL em um destino especificado.
Manter e atualizar certificados ou chaves públicas fixados é essencial para preservar a confiança, a segurança e a integridade dos canais de comunicação. Ao mantê-los atualizados, podemos reduzir os riscos associados ao comprometimento, vencimento e revogação de certificados, além de garantir conexões seguras e autenticadas.
Abra a pasta snyk-tls no terminal e execute o comando abaixo.
Esse comando gera um arquivo cert.pem com o certificado público de google.com.
Em seguida, crie um arquivo main.js na pasta do projeto. Cole o código abaixo.
O código acima importa os módulos necessários e define duas variáveis: certPath e command. certPath define o caminho para o arquivo do certificado. command contém o comando de shell que gera a impressão digital SHA-256 do certificado.
A função generate_SHA256_fingerprint() usa a função exec para executar o comando openssl, que gera a impressão digital SHA-256 do certificado. Essa função retorna uma promise que é resolvida com a impressão digital.
A função verifyCertificate() define um objeto de opções para configurar a solicitação HTTPS. Esse objeto especifica hostname, port, path e method. Também define a função checkServerIdentity() para verificar o certificado do servidor. Essa função garante que o certificado pertença ao host ao qual estamos nos conectando e verifica se a impressão digital corresponde à impressão fixada.
Para testar esse script, execute o comando node main.js no terminal. Você deverá receber a seguinte saída.
Para atualizar um certificado ou uma chave fixados, abrimos o arquivo da API e executamos o comando openssl que gera o arquivo cert.pem. Se usarmos um serviço de cofre externo para armazenar certificados ou chaves públicas fixados, podemos editar os valores diretamente nesse serviço, sem modificar o código da aplicação. Veja algumas situações que exigem a atualização dos certificados fixados:
Vencimento de certificados ou chaves públicas
Vazamentos de dados
Revogação pelo emissor
Políticas de conformidade que exigem a rotação do certificado após um período determinado
Conclusão
Neste artigo, aprendemos a implementar o pinning de SSL/TLS em aplicações Node.js. O pinning de SSL/TLS adiciona uma camada extra de segurança ao verificar a chave pública ou o certificado do servidor em relação a uma cópia armazenada localmente. Ele ajuda a proteger nossas aplicações contra ataques MITM e outras vulnerabilidades relacionadas a certificados.
O Node.js tem módulos integrados, como o HTTPS, que oferecem suporte ao pinning de certificados. Podemos aplicar o pinning de SSL/TLS comparando a chave pública durante o handshake TLS e encerrando a conexão em caso de divergência. Também é essencial tratar os erros adequadamente para evitar perder o acesso em situações excepcionais, como quando um certificado ou uma chave pública vence ou é revogada pelo emissor. Simular ataques, comparar hashes de chaves e atualizar certificados ou chaves são boas práticas para testar o pinning de SSL/TLS e garantir sua eficácia. Outra boa prática é armazenar as chaves públicas com segurança.
Com o pinning de SSL/TLS, podemos reforçar a segurança geral das aplicações Node.js e oferecer uma experiência confiável e segura aos usuários.
Comece a jogar Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo à gravação sob demanda do nosso workshop virtual introdutório.



