Como prevenir ataques de injeção de SQL no Node.js
Lucien Chemaly
20 de fevereiro de 2024
0 minutos de leituraÀ medida que aumenta a dependência de sistemas de software, também surgem novas ameaças à segurança. Uma ameaça importante para desenvolvedores, especialmente para quem trabalha com Node.js, é a injeção de SQL.
A injeção de SQL é um ataque malicioso em que código SQL nocivo é inserido em um sistema, expondo informações confidenciais, corrompendo ou excluindo dados e, às vezes, concedendo acesso não autorizado a invasores. Combater essa ameaça é difícil e reforça a necessidade de proteger suas aplicações Node.js.
Neste artigo, você vai entender por que os ataques de injeção de SQL representam uma ameaça significativa e como proteger suas aplicações Node.js contra eles.
Entenda a injeção de SQL em aplicações Node.js
Os ataques de injeção de SQL ocorrem principalmente quando uma aplicação Node.js não trata corretamente as entradas do usuário. Quando essas entradas são usadas em uma consulta SQL sem validação, sanitização ou construção adequada da consulta, abre-se uma brecha para que invasores manipulem a consulta, obtendo acesso não autorizado ou vazando dados. Para conhecer as vulnerabilidades antigas e recentes do Node.js, consulte a lista na Snyk Vulnerability Database.
Aplicação Node.js com Express vulnerável à injeção de SQL
Para entender melhor como funciona a injeção de SQL, vamos criar rapidamente uma aplicação vulnerável usando Node.js, Express e um banco de dados PostgreSQL. A aplicação recebe dados de um formulário, monta uma consulta SQL e a executa no banco de dados para buscar informações.
Comece baixando e instalando o Node.js na sua máquina. O Node.js é o ambiente de execução que executa seu código JavaScript no servidor.
Em seguida, crie um diretório para o projeto (por exemplo, vulnerable-app) e acesse esse diretório no terminal com o comando cd vulnerable-app.
No diretório do projeto, execute o comando npm init -y. Ele cria um arquivo package.json com valores padrão, que funciona como manifesto do projeto Node.js.
Instale o Express e a biblioteca pg com o comando npm install express pg. O Express é um framework leve para aplicações web, e pg é um cliente Node.js para PostgreSQL.
Em seguida, baixe e instale o PostgreSQL. Depois da instalação, crie um banco de dados chamado vulnerable_db. Nesse banco, crie uma tabela chamada users com uma coluna chamada name. Use o seguinte comando SQL:
Para obter mais informações sobre como instalar e executar o PostgreSQL, consulte esta documentação da W3Schools.
Crie um arquivo chamado app.js e adicione o seguinte código:
Este código inicializa um servidor Express e configura conexões com um banco de dados PostgreSQL usando a biblioteca pg. O servidor é configurado para processar entradas codificadas em URL e em JSON.
São definidas duas rotas: POST /search e POST /create. A rota /search recebe dados do usuário no corpo da requisição, monta uma consulta SQL e a executa no banco de dados, retornando o resultado. No entanto, ela tem uma vulnerabilidade de injeção de SQL, pois concatena a entrada do usuário à consulta. A rota /create extrai um valor name do corpo da requisição, verifica se ele foi informado e, então, monta uma consulta SQL parametrizada e segura para inserir um novo usuário no banco de dados, retornando o registro criado. Por fim, o servidor começa a escutar na porta 3000 e exibe uma mensagem no console para indicar que está pronto.
Observação: Substitua your-username, your-password, your-database, your-host e your-port pelas configurações que você definiu para o PostgreSQL.
Como não há validação nem sanitização das entradas, o código é vulnerável à injeção de SQL. Um invasor pode inserir no formulário um valor como ' OR '1'='1'; --. Essa entrada encerra a consulta original e a modifica para SELECT * FROM users WHERE name = '' OR '1'='1'; --';, que retorna todos os registros da tabela users, pois '1'='1' é sempre verdadeiro. Este é um exemplo clássico de injeção de SQL por concatenação de strings.
Agora que está tudo configurado, é hora de iniciar o servidor. Execute o comando node app.js no terminal. Isso inicia o servidor, e você deverá ver a mensagem Server is running on port 3000, indicando que ele está funcionando corretamente:

Para testar a aplicação, crie alguns usuários pelo terminal ou shell:
Em seguida, se quiser buscar um usuário específico para verificar sua identidade, atualizar dados ou realizar auditorias e monitoramento, envie uma solicitação de busca dos dados do usuário. Execute o comando a seguir:
A saída deverá ser semelhante a esta:
Agora, injete SQL para obter todos os usuários usando o seguinte comando:
A saída deverá ser semelhante a esta:
Neste comando, os dados JSON ficam entre aspas duplas externas (" ") para formar uma string JSON completa, enquanto as aspas internas dos dados JSON são escapadas com uma barra invertida (\) para que sejam incluídas corretamente na string. O valor de userInput é definido como ' OR '1'='1'; -- e, como explicado anteriormente, manipula a consulta SQL para retornar todos os registros de usuários, alterando a condição para que seja sempre verdadeira.
Como prevenir vulnerabilidades de injeção de SQL no Node.js
Agora que você sabe como é fácil ocorrerem ataques de injeção de SQL, veja algumas maneiras de proteger sua aplicação e garantir que ela seja segura para seus usuários.
Use marcadores de posição nas consultas
Evitar montar consultas SQL por concatenação de strings é essencial para prevenir a injeção de SQL. Invasores podem manipular consultas ao inserir código SQL malicioso nos campos de entrada. Em vez disso, use marcadores de posição para garantir que as entradas do usuário sejam tratadas como dados, e não como código executável:
Use consultas preparadas
Uma das maneiras mais eficazes de prevenir ataques de injeção de SQL é usar consultas preparadas. Elas garantem que as entradas do usuário sejam sempre tratadas como dados, e não como código executável.
Veja como modificar a rota /search para usar consultas preparadas com a biblioteca pg:
Neste código, a consulta preparada é definida como um objeto com a propriedade text para a consulta SQL e a propriedade values para a entrada do usuário. Essa separação permite definir o modelo da consulta SQL uma única vez e fornecer valores diferentes para o marcador de posição a cada execução. Assim, as entradas do usuário são tratadas com mais segurança e eficiência nas consultas SQL.
Valide e sanitize as entradas do usuário
Verificar as entradas do usuário é essencial para garantir que elas atendam a requisitos específicos, como formato correto, comprimento ou intervalo de valores. Bibliotecas de validação como joi ou express-validator simplificam esse processo. Elas oferecem regras e funções de validação predefinidas, facilitando a aplicação dos requisitos e a automação das verificações.
Além disso, sanitizar as entradas para remover ou escapar caracteres potencialmente nocivos é essencial para manter um ambiente de aplicação seguro e robusto. A sanitização de entradas consiste em limpar os dados fornecidos pelos usuários para evitar danos ou comportamentos inesperados durante o processamento pela aplicação.
Veja como implementar a validação e a sanitização usando a biblioteca express-validator:
Use as versões mais recentes de bibliotecas ORM e SQL
Use sempre as versões mais recentes de bibliotecas ORM e SQL. Os mantenedores dessas bibliotecas lançam atualizações e correções com frequência para resolver vulnerabilidades de segurança conhecidas:
Revise o código regularmente e realize auditorias de segurança
Faça revisões de código e auditorias de segurança regulares para identificar vulnerabilidades o quanto antes. Use ferramentas como npm audit ou snyk para automatizar a identificação de vulnerabilidades conhecidas nas suas dependências.
Detecte vulnerabilidades com a extensão Snyk IDE para Visual Studio Code
Snyk é uma ferramenta de segurança criada para desenvolvedores que ajuda a identificar e corrigir vulnerabilidades no código e em dependências de código aberto. Ela se integra perfeitamente ao fluxo de desenvolvimento, monitorando e analisando continuamente falhas de segurança, inclusive as relacionadas à injeção de SQL.
Além de identificar vulnerabilidades, a Snyk também cria pull requests com correções automatizadas, facilitando a resolução e a prevenção de possíveis problemas de segurança. A plataforma se integra a várias ferramentas de desenvolvimento, como GitHub, GitLab e Bitbucket, e oferece uma extensão dedicada para o Visual Studio Code, com feedback em tempo real durante a programação.
Configure uma extensão da Snyk
É fácil configurar uma extensão da Snyk. Comece baixando e instalando o Visual Studio Code, caso ainda não tenha feito isso. Depois, abra o Visual Studio Code e acesse a visualização Extensions pressionando Ctrl + Shift + X no Windows ou Command + Shift + X no macOS.
Na visualização Extensions, digite "Snyk" na barra de pesquisa e clique no botão Install da extensão Snyk:

Após a instalação, você verá a extensão Snyk na barra lateral esquerda do Visual Studio Code. Clique nela e, em seguida, em Trust workspace and connect. Para usar a extensão, entre na sua conta Snyk. Se ainda não tiver uma conta, você pode criar uma gratuitamente:

Em seguida, será solicitado que você entre na conta e faça a autenticação. Depois, deverá aparecer a mensagem Authenticated:

Depois de instalada e configurada, a extensão Snyk analisa automaticamente seu projeto em busca de vulnerabilidades conhecidas, incluindo possíveis riscos de injeção de SQL.
Acesse sua conta na plataforma Snyk e siga as instruções para ativar o Snyk Code. Ativar o Snyk Code é importante para que a Snyk detecte vulnerabilidades no código, como injeções de SQL.
Se a opção Snyk Code não estiver ativada na sua conta Snyk, a extensão Snyk para Visual Studio Code não detectará injeções de SQL relacionadas a más práticas no código. Ela detectará apenas vulnerabilidades relacionadas a bibliotecas desatualizadas e similares.
A Snyk não se limita a identificar vulnerabilidades: ela também oferece sugestões e referências para corrigir os problemas. Esse recurso pode ser muito útil, especialmente ao trabalhar com bases de código grandes ou prazos apertados.
Todo o código deste tutorial está disponível no repositório do GitHub a seguir.
Conclusão
Neste artigo, você aprendeu como a injeção de SQL ocorre em aplicações Node.js e conheceu várias estratégias para preveni-la. De atualizar bibliotecas ORM e SQL e sanitizar entradas de usuários a usar marcadores de posição nas consultas e aproveitar a extensão da Snyk para Visual Studio Code, você tem várias maneiras de proteger suas aplicações Node.js contra ataques de injeção de SQL.
A extensão Snyk não só ajuda a identificar vulnerabilidades de injeção de SQL, como também ensina a resolvê-las, funcionando como uma mentora virtual de segurança. Ao integrar a Snyk ao seu fluxo de desenvolvimento, você deixa de apenas reagir às ameaças e passa a preveni-las, mantendo suas aplicações robustas e seguras antes de chegarem à produção.
À medida que você avança no desenvolvimento com Node.js, lembre-se de que segurança não é uma tarefa pontual, mas um processo contínuo. Mantenha-se atualizado sobre as práticas recomendadas de segurança mais recentes, continue aprendendo e mantenha suas aplicações seguras. Seus usuários agradecem, e você fica mais tranquilo sabendo que seus dados e os deles continuam protegidos.
Comece a resolver desafios de Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo ao nosso workshop virtual introdutório sob demanda.



