Skip to main content

Como prevenir vulnerabilidades de injeção de logs em aplicações JavaScript e Node.js

Escrito por
feature open source

26 de setembro de 2024

0 minutos de leitura

Em muitas aplicações corporativas padrão, o registro consistente de logs atende a diversas finalidades. Ele ajuda as empresas a identificar e corrigir erros, oferece insights analíticos valiosos e permite testar novas soluções. No entanto, isso também faz da injeção de logs uma das formas mais comuns de hackers sequestrarem aplicações ou até mesmo obterem acesso a informações confidenciais de usuários. Vulnerabilidades na forma como as aplicações registram dados podem permitir que invasores insiram código malicioso nos logs, comprometendo a integridade e a confidencialidade da sua aplicação.

Neste artigo, você vai conhecer especificamente as vulnerabilidades de injeção de logs em Node.js. Vai descobrir como esses ataques funcionam e aprender maneiras eficazes de evitá-los.

O que é uma vulnerabilidade de injeção de logs?

Para registrar informações, algumas aplicações gravam os logs em um arquivo externo ou usam uma API externa para enviá-los. A injeção de logs ocorre quando um invasor manipula dados de entrada para inserir código malicioso nos logs da aplicação. Em geral, esses logs são usados para depuração, monitoramento e auditoria.

Quando ocorre uma injeção de logs, o invasor pode poluir os logs ou até mesmo executar código no contexto da aplicação, o que leva a diversos riscos de segurança.

Exemplo de uma aplicação Node.js vulnerável

Imagine uma aplicação Node.js simples que usa o framework web Express para registrar dados fornecidos pelo usuário sem validação ou sanitização adequada. O trecho de código a seguir ilustra essa vulnerabilidade:

const express = require('express');
const app = express();

app.get('/log', (req, res) => {
  const userInput = req.query.data;
  console.log('INFO: ' + userInput);
  res.send('Data logged successfully.');
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

Quando o servidor estiver no ar e funcionando localmente, você poderá fazer uma requisição GET usando ferramentas de teste de API, como o Insomnia, para verificar se tudo está funcionando como esperado. Neste caso, você pretende registrar o nome de usuário de um formulário e verificar como ficam os logs do servidor. Adicione os dados no formato esperado pelo servidor e envie a requisição. Você receberá um 200 OK e uma mensagem dizendo: "Data logged successfully.":

Cliente de API exibindo uma solicitação POST para registrar dados e a resposta de sucesso “Dados registrados com sucesso”

Se você conferir os logs no servidor, verá que tudo parece estar sendo registrado como esperado. Como você adicionou o valor charlie aos parâmetros de dados, o log mostra INFO: charlie sendo registrado no servidor:

Terminal mostrando um servidor Node.js Express iniciado na porta 3000, com um log INFO exibindo “charlie”

Uma forma de alguém mal-intencionado explorar a maneira como essa aplicação registra dados é inserir logs falsos usando o parâmetro data. Neste exemplo, bastaria adicionar um texto extra à consulta:

Cliente de API mostrando uma solicitação GET para localhost com um payload de injeção de logs codificado e uma resposta 200 bem-sucedida.
Terminal mostrando um servidor Node.js Express iniciando na porta 3000 e registrando a exclusão de usuários

Por exemplo, alguém mal-intencionado pode adicionar INFO: User deleted como um log falso. Ao encontrar esse registro, a equipe de desenvolvimento pode ser induzida ao erro e gastar tempo e recursos tentando descobrir por que a aplicação está excluindo usuários quando alguém envia um nome de usuário — tudo porque um invasor decidiu inserir caracteres adicionais em um formulário de entrada.

Embora seja simplista, este exemplo ajuda você a entender o que são injeções de logs em geral. Outros tipos de injeção podem incluir a adição de logs falsos de erros ou de informações de usuários, simplesmente modificando a mensagem do log ou, pior ainda, inserindo injeções de comandos que permitiriam aos invasores manipular dados internos diretamente.

Como prevenir vulnerabilidades de injeção de logs em Node.js

Para reduzir as vulnerabilidades de injeção de logs nas suas aplicações Node.js, considere adotar algumas destas práticas comuns:

Sanitize as entradas do usuário

Na maioria dos casos, as entradas do usuário devem ser validadas e sanitizadas antes de serem registradas. Isso significa verificar cuidadosamente tudo o que será registrado para excluir caracteres que possam ser confundidos com outra entrada de log e/ou permitir apenas os caracteres apropriados.

No exemplo anterior, uma forma de sanitizar os logs seria incluir uma expressão regular que filtre e permita apenas letras do alfabeto. Assim, caracteres especiais ou números não seriam adicionados ao log:

app.get('/log', (req, res) => {
  const userInput = req.query.data
  const sanitizedInput = userInput.replace(/[^a-zA-Z]+/, '')
  console.log('INFO: Username: ', sanitizedInput);
  res.send('Data logged successfully.');
});
Terminal mostrando o log de um servidor Node.js Express com uma entrada de nome de usuário e a mensagem “INFO: User deleted”

Uma ressalva importante: escolher a forma certa de sanitizar dados pode ser complicado. Neste exemplo, o nome de usuário de quem usar números (por exemplo, 123) será alterado nos logs.

Embora a sanitização das entradas possa ajudar a identificar logs maliciosos, as contrapartidas exigem que os desenvolvedores tenham cuidado extra com o que filtram e como fazem isso. Por exemplo, escrever expressões regulares incorretamente pode resultar em vulnerabilidades ReDOS que paralisam aplicações Node.js. Usar pacotes npm de terceiros, como validator.js, é uma boa opção para não reinventar a roda, mas mantenha essas dependências sempre atualizadas.

Tenha cuidado com o que você registra

Cada aplicação é única. Nenhum padrão de registro de logs atende a todas as necessidades que podem surgir em cada aplicação. É importante pensar nas informações que você precisa registrar e em quem vai consultá-las.

Os logs no nível DEBUG podem ajudar os desenvolvedores a rastrear o que acontece na aplicação e como o usuário navega de um componente para outro ou como as informações fluem de uma origem para outra. Já os logs nos níveis WARN ou ERROR ajudam as equipes de engenharia a identificar possíveis bugs com antecedência e entender o que causa falhas ou mau funcionamento na aplicação. O segredo é registrar apenas o necessário, nada além disso, e considerar o que aconteceria se invasores obtivessem acesso aos seus logs.

Como explica este artigo da Snyk sobre vulnerabilidades de logging, enviar informações confidenciais para um serviço externo de logs pode expor dados a invasores. Em geral, é recomendável evitar o registro de informações confidenciais ou sensíveis, como senhas, chaves de API ou dados pessoais. Se precisar registrá-las, implemente controles de acesso adequados e considere usar variáveis de ambiente (como no GitHub Actions) e sistemas de gerenciamento de chaves para gerenciar dados de configuração confidenciais com segurança.

Além de pensar no que você registra, é preciso considerar como faz isso. O logging estruturado pode organizar melhor os dados registrados, facilitando sua identificação pelos desenvolvedores. Por exemplo, em vez de registrar diretamente os dados do usuário como uma string, como no exemplo anterior, você pode usar um objeto JSON para identificar de forma mais clara o que está sendo registrado:

app.get('/log', (req, res) => {
  const userInput = req.query.data;
  const log = {username: userInput, 'action':'submitted username', 'time': new Date()}
  console.log(log)
  res.send('Data logged successfully.');
});

Mais importante ainda, estruturar os logs dessa forma pode dificultar a injeção de registros por invasores, já que eles também precisariam manipular várias propriedades do objeto de log (por exemplo, action ou time). Se não fizerem isso, podem acabar revelando o que estão tentando fazer:

Saída do terminal mostrando um servidor Node.js Express na porta 3000 e o registro de um nome contendo uma mensagem injetada após uma quebra de linha

Embora este exemplo de registro de um objeto JSON seja simplista, existem bibliotecas de logging (que veremos a seguir) que oferecem logging estruturado como uma alternativa útil ao tradicional console.log.

Use uma biblioteca de logging em vez de console.log

Muitas bibliotecas de logging oferecem mais controle e segurança sobre as saídas de log do que console.log, pois normalmente incluem recursos integrados de sanitização e filtragem para evitar ataques de injeção de logs. Elas também permitem que os desenvolvedores controlem quais logs aparecem em cada ambiente (teste ou produção), escolham para onde os logs serão enviados (arquivo local, banco de dados e/ou API de terceiros) e configurem os logs para facilitar o rastreamento.

Uma biblioteca que recomendamos é o pino, um pacote bem mantido e, de modo geral, confiável, sem vulnerabilidades de segurança conhecidas.

O Pino é altamente otimizado para desempenho e pode ser configurado para incluir timestamps em cada registro de log. Ele oferece suporte a logging estruturado e aos níveis padrão de log do sistema. Essa complexidade e estrutura adicionais podem reforçar a segurança e reduzir a probabilidade de os logs serem comprometidos por invasores.

Use a extensão Snyk para IDE no VS Code para detectar vulnerabilidades

A Snyk oferece uma extensão gratuita para IDE do Visual Studio Code (VS Code) que ajuda a detectar vulnerabilidades de injeção de logs (entre outras) no seu código Node.js. Veja como configurá-la:

Acesse a guia Extensions no VS Code e pesquise "Snyk" para encontrar a extensão "Snyk Security - Code, Open Source Dependencies, Iac Configurations". Clique em Install:

Marketplace de extensões do Visual Studio Code mostrando a página da extensão Snyk Security, com um botão Instalar

Após a instalação, a Snyk solicitará que você autentique sua conta conectando-a à IDE. Clique em Connect VS Code with Snyk. Uma página externa da Snyk será aberta para pedir sua permissão de conexão. Nela, clique em Authenticate.

Depois de autenticar, clique em Scan para analisar seu código em busca de vulnerabilidades. Você também pode configurar a extensão conforme necessário:

Painel de segurança do Snyk Code em um editor de código, mostrando seis vulnerabilidades e 55 problemas de qualidade de código em arquivos JavaScript

A extensão Snyk para IDE analisa automaticamente seu código em busca de vulnerabilidades de injeção de logs. Além disso, durante a análise, a Snyk destaca outros possíveis problemas de segurança no seu código, como segredos codificados diretamente ou vulnerabilidades de path traversal, e oferece insights e recomendações práticas para ajudar você a proteger sua aplicação.

Comece a usar o Snyk gratuitamente

Não é necessário informar um cartão de crédito.

Crie uma conta com Bitbucket e veja mais opções

Ao usar o Snyk, você concorda em cumprir nossas políticas, incluindo os Termos de Serviço e a Política de Privacidade.

Leia mais

illustration hero ai
Blog

PHP corrige duas vulnerabilidades críticas de RCE sem autenticação (CVE-2026-109618, CVE-2026-109619): atualize agora

Duas falhas críticas no ciclo de requisições do PHP podem permitir execução remota de código sem autenticação. Atualize para uma versão corrigida ou instale um backport do fornecedor para versões mais antigas.

blog feature ai lilac
Blog

Transforme seu backlog de vulnerabilidades em pull requests com remediação agentiva

O Evo Remediation Agent está em Open Preview e traz a resolução automatizada de dependências para o Evo Agentic AppSec. Agora, as equipes de AppSec podem executar campanhas contínuas de remediação

AI Background min crop
Blog

A IA está acionando todos os riscos que você aceitou: sete insights do painel de segurança de IA sem filtros

A IA está tornando os ataques mais baratos e rápidos, expondo riscos que as organizações já carregam. Quatro líderes de segurança explicam por que a defesa na velocidade das máquinas e a correção mais rápida são essenciais.