Aikido

Detecção e bloqueio de ataques de injeção SQL em JavaScript

Escrito por
Mackenzie Jackson

Por que você está aqui?

Você já ouviu falar sobre ataques de injeção de SQL em JavaScript antes, mas não tem certeza de como eles se manifestam na prática ou se precisa se preocupar com eles. Talvez você esteja tentando descobrir o quão ruim isso pode ser.

Em resumo, se você está desenvolvendo aplicativos usando bancos de dados SQL, como MySQL e PostgreSQL, você está em risco — você não está seguro contra métodos de ataque que afligem desenvolvedores e seus bancos de dados há décadas. Como desenvolvedor, a responsabilidade é sua de implementar salvaguardas que protejam os dados do usuário e garantam que sua infraestrutura subjacente nunca seja invadida, explorada ou controlada.

Todas as novas ferramentas dizem que estão ajudando você, mas elas apenas tornam o desenvolvimento mais complexo.

Você pode adicionar um mapeador objeto-relacional (ORM) como Sequelize e TypeORM para simplificar como você trabalha com bancos de dados SQL como MySQL e PostgreSQL, mas eles não o isentam completamente do risco. Web application firewalls (WAFs) ajudam a bloquear ataques no nível de rede, mas exigem infraestrutura cara e manutenção constante. Scanners de código podem ajudar a identificar falhas óbvias, mas fazem muito menos pelos "desconhecidos desconhecidos" e pelas técnicas de dia zero à espreita.

Apresentaremos a você uma imagem clara de como são os ataques de injeção de SQL, o risco que eles representam e os erros de desenvolvimento que os tornam possíveis. Em seguida, faremos algo ainda melhor, guiando você pela instalação de um hotfix global para que você saiba, com certeza, que seus aplicativos estão seguros.

Ataques de injeção de SQL: exemplos e implicações

A definição mais básica de um ataque de injeção de SQL é quando um aplicativo permite que entradas de usuário não validadas e não sanitizadas executem consultas de banco de dados, permitindo que um atacante leia o banco de dados SQL, modifique registros ou os exclua à vontade.

Como de costume, o XKCD ilustra o perigo do SQL melhor do que a maioria dos cenários sombrios que poderíamos imaginar:

A famosa tirinha "Bobby Tables", ilustrando um possível ataque de injeção de SQL em JavaScript.
Digite a legenda (opcional)

Como é um aplicativo JavaScript vulnerável?

Vamos começar com um exemplo simples de pseudocódigo: um aplicativo JavaScript com um elemento de entrada que permite aos usuários pesquisar um banco de dados de gatos. No exemplo de código JavaScript abaixo, o aplicativo responde a requisições POST no caminho /cats para extrair a entrada do usuário do corpo da requisição e se conecta ao banco de dados com uma consulta para retornar todos os gatos com um ID correspondente. O aplicativo então exibe o gato usando a resposta JSON.

app.post("/cats", (request, response) => {
	const query = `SELECT * FROM cats WHERE id = ${request.body.id}`;
	connection.query(query, (err, rows) => {
    	if(err) throw err;
        response.json({
        	data: rows
		});  
	});
});


Embora este exemplo possa parecer inócuo para aqueles não familiarizados com ataques de injeção SQL, ele é extremamente vulnerável. Notavelmente, o aplicativo não tenta validar ou sanitizar a entrada do usuário para strings ou métodos de codificação potencialmente perigosos, e concatena a entrada do usuário diretamente na query SQL, o que permite aos atacantes múltiplas oportunidades de ataque usando métodos comuns de injeção SQL que existem há décadas.

Exemplos de payloads de ataque SQL em JavaScript

A injeção SQL depende de enganar seu banco de dados MySQL ou PostgreSQL para que ele execute ações ou responda com dados fora do escopo esperado, devido à forma como seu aplicativo gera queries SQL.

O 1=1 é sempre verdadeiro o ataque pode retornar a tabela inteira de gatos com truques como apóstrofos ou aspas, porque 1=1 é de fato sempre VERDADEIRO:

  • O usuário insere: BOBBY TABLES' OR 1='1
  • O banco de dados executa a query SQL: SELECT * FROM Users WHERE Cat = BOBBY TABLES OR 1=1;

Da mesma forma, atacantes podem explorar um = é sempre verdadeiro ataque para retornar todos os gatos, porque ""="" é sempre VERDADEIRO:

  • O usuário insere: " OR ""="
  • O banco de dados executa a query SQL: SELECT * FROM Cats WHERE CatId ="" or ""="";

Atacantes frequentemente exploram como os bancos de dados lidam com comentários inline, e, ao inserir comentários (/* ... */) em uma query, eles podem ofuscar sua intenção ou contornar filtros.

  • O usuário insere: DR/*hello world*/OP/*sneak attack*/ TABLE Cats;
  • O banco de dados executa a query SQL: DROP TABLE Cats;

Outra estratégia comum de injeção SQL em JavaScript é o query stacking, que permite aos atacantes começar com uma string inócua, e então usar um ponto e vírgula (;) para terminar essa instrução e iniciar outra contendo sua injeção. Atacantes frequentemente usam o query stacking para deletar bancos de dados inteiros de uma só vez com um comando DROP TABLE:

  • O usuário insere: Bobby; DROP TABLE Cats --
  • O aplicativo constrói sua query SQL: const query = "SELECT * FROM Cats WHERE CatId = " + input;
  • O banco de dados executa a query SQL: SELECT * FROM Cats WHERE CatId = BOBBY; DROP TABLE Cats;

E quanto aos ataques de injeção NoSQL?

Ataques de injeção NoSQL são igualmente perigosos para a segurança do seu aplicativo e dos dados do usuário, mas afetam apenas stacks de tecnologia que utilizam bancos de dados como o MongoDB. A principal diferença está no estilo dos ataques, pois as queries SQL e NoSQL utilizam sintaxes completamente únicas que não se traduzem de uma categoria para a outra.

Se você está usando um banco de dados SQL, você não está em risco de ataques de injeção NoSQL, e vice-versa.

O caminho básico: corrigir manualmente todas as suas vulnerabilidades de injeção SQL

Neste ponto, você pode estar menos interessado em como são todos os possíveis truques de injeção e mais interessado em como proteger os dados que você tem no MySQL ou PostgreSQL.

  • Use queries parametrizadas: SQL possui funcionalidade para desconectar a execução de queries e valores, protegendo o banco de dados contra ataques de injeção. Com o exemplo de JavaScript/Node.js de cima, você pode empregar um placeholder em sua query SQL com um ponto de interrogação (?). O connection.query() método então recebe o parâmetro em seu segundo argumento, fornecendo os mesmos resultados em um método à prova de injeção.
app.post("/cats", (request, response) => {  
	const query = `SELECT * FROM Cats WHERE id = ?`;  
    const value = request.body.id;  
    connection.query(query, value, (err, rows) => {    
    	if(err) throw err;    
        response.json({      
        	data: rows    
		});  
	});
});

  • Valide e sanitize a entrada do usuário: Embora queries parametrizadas possam ajudar a proteger seu banco de dados SQL contra intrusão e ataque, você também pode impedir que usuários insiram strings potencialmente perigosas em seu aplicativo.

    Uma opção é adicionar bibliotecas de código aberto para sanitização e validação ao seu aplicativo. Por exemplo, você pode usar validator.js no ecossistema JavaScript/Node.js para verificar se um usuário está tentando inserir um endereço de e-mail real — e não um ataque de injeção SQL — em seu formulário de inscrição.

    Você também pode desenvolver validadores personalizados baseados em regex para realizar um trabalho semelhante, mas terá um caminho extremamente demorado e complexo pela frente, com pesquisa e muitos testes manuais. Além disso, você consegue realmente interpretar este exemplo de regex para validação de e-mail?

    const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

    A mesma ideia se aplica à prevenção de strings como …’ OR 1-’1. Você pode tentar pesquisar e eliminar todas essas oportunidades por conta própria, mas provavelmente preferiria gastar seu tempo construindo novos recursos.

  • Implante WAFs ou plataformas de segurança baseadas em agentes: Embora essas soluções possam bloquear ataques SQL antes mesmo de tocarem seu aplicativo, ou pelo menos notificá-lo em tempo real à medida que os ataques acontecem, elas vêm com algumas ressalvas.

    Primeiro, elas são frequentemente caras e exigem que você lance uma nova infraestrutura on-premises ou na Cloud, o que é muitas vezes muito mais complexo do que você esperava como um desenvolvedor que apenas quer enviar para produção. Segundo, elas exigem mais manutenção manual para atualizar o conjunto de regras, distraindo-o de outras intervenções manuais para injeção SQL. Finalmente, elas frequentemente adicionam mais carga computacional, ou redirecionam todas as requisições através de sua plataforma para análise, adicionando latência e prejudicando a experiência do usuário final.

O grande problema é que as oportunidades para ataques de injeção SQL são como ervas daninhas — você pode eliminá-las todas de uma vez usando essas ferramentas, mas deve estar constantemente vigilante sobre toda a sua base de código para garantir que nunca mais brotem.

Um caminho alternativo para resolver ataques de injeção SQL em JavaScript: Aikido Firewall

A Aikido Security lançou recentemente o Firewall, um motor de segurança gratuito e de código aberto que o protege autonomamente contra ataques de injeção SQL — e muito mais.

Se você não está usando Node.js, saiba que começaremos a dar suporte a outras linguagens e frameworks no futuro. Você sempre pode assinar nossa newsletter de produtos para saber exatamente quando o Firewall se expandir para além do mundo JavaScript ou nos enviar um e-mail para hello@aikido.dev se você gostaria de sugerir uma linguagem específica.

Testando um aplicativo vulnerável a injeção SQL em JavaScript

Vamos usar um aplicativo de exemplo fornecido com o repositório de código aberto para demonstrar como o Aikido Firewall funciona. Você também precisará de Docker/Docker Compose para implantar um banco de dados MySQL local.

Comece fazendo um fork do repositório firewall-node e clonando esse fork para sua estação de trabalho local.

git clone https://github.com/<YOUR-GITHUB-USERNAME>/firewall-node.gitcd firewall-node


Use Docker para implantar um banco de dados MySQL local na porta 27015. Este arquivo docker-compose.yml também cria Containers s3mock, MongoDB e PostgreSQL, pois foi criado para ajudar a equipe Aikido a testar como o Firewall bloqueia vários ataques.

docker-compose -f sample-apps/docker-compose.yml up -d


Em seguida, inicie o aplicativo de exemplo:

node sample-apps/express-mysql2/app.js


Abra http://localhost:4000 no seu navegador para conferir o aplicativo de gatos muito simples. Na área de texto, digite alguns nomes de gatos e clique no Adicionar botão. Para testar a injeção SQL, você pode clicar no Testar injeção link ou digitar o seguinte na área de texto: Kitty'); DELETE FROM cats;-- H e clique em Adicionar novamente. De qualquer forma, o aplicativo permite que você empilhe várias consultas juntas usando alguns comentários de consulta astutos, excluindo todo o banco de dados de gatos.

Como isso acontece? Como alertamos anteriormente, este aplicativo simplesmente anexa qualquer entrada do usuário no final da consulta SQL, o que é inerentemente inseguro.

const query = `INSERT INTO cats(petname) VALUES ('${name}');`


As consequências podem ser pequenas aqui, mas não é difícil imaginar como este erro muitas vezes honesto pode ter consequências desastrosas para o seu aplicativo em produção.

Bloqueando injeção SQL em JavaScript com Aikido Firewall

Agora vamos ver como nosso motor de segurança de código aberto bloqueia rapidamente ataques de injeção SQL em JavaScript sem corrigir manualmente cada interação com o banco de dados em seu código.

Se você ainda não tem uma conta Aikido, vá em frente e crie uma gratuitamente. Se você já tem uma, faça login e conecte sua conta GitHub. Durante esse processo, conceda ao Aikido acesso para ler seu fork do firewall-node projeto.

Vá para o dashboard do Firewall e clique em Adicionar Serviço. Dê um nome ao seu serviço e, mais uma vez, escolha seu fork para o firewall-node projeto.

Adicionando Firewall a um projeto Node.js para proteger contra ataques de injeção SQL em JavaScript.
Digite a legenda (opcional)

O Aikido então o instrui sobre como instalar e implementar o Aikido Firewall. Como estamos usando o aplicativo de exemplo, esse trabalho já está feito para você, mas é uma referência útil sobre como você faria para levar nosso motor de segurança de código aberto para todos os seus aplicativos Node.js que podem ser vulneráveis a ataques de injeção SQL em JavaScript.

Digite a legenda (opcional)

Clique no Gerar Token botão para criar um token para permitir que o Aikido Firewall passe com segurança informações sobre ataques de injeção SQL bloqueados para a plataforma de segurança Aikido. Copie o token gerado, que começa com AIK_RUNTIME…, e volte ao seu terminal para executar novamente o aplicativo de exemplo, mas agora com o Firewall totalmente habilitado no modo de bloqueio:

AIKIDO_TOKEN=<YOUR-AIKIDO-TOKEN> AIKIDO_DEBUG=true AIKIDO_BLOCKING=true node sample-apps/express-mysql2/app.js


Abra localhost:4000 e invoque novamente o ataque de injeção SQL incluído. Desta vez, o Aikido irá bloqueá-lo no navegador, gerar saída para os logs do seu servidor web local e gerar um novo evento. Clique nele para ver detalhes abrangentes sobre a tentativa de injeção SQL, incluindo o payload e onde seu aplicativo gerou a consulta SQL perigosa.

Um exemplo de Firewall bloqueando um ataque de injeção SQL em JavaScript.
Digite a legenda (opcional)

Em vez de se preocupar em proteger seus aplicativos para sempre contra ataques de injeção SQL em JavaScript, tanto os críticos quanto os ainda não vistos, o Aikido Firewall oferece bloqueio abrangente e observabilidade sofisticada que o mantém informado sobre as fontes de ataque, payloads comuns e possíveis pontos fracos.

O que vem a seguir?

Você pode instalar e implementar o Aikido Firewall em todos os seus aplicativos baseados em Node.js gratuitamente. Nosso motor de segurança embarcado de código aberto protege sua infraestrutura e dados de usuário contra ataques de injeção SQL em JavaScript, injeção de comando, poluição de protótipo, path traversal e muito mais em breve.

Não estamos dizendo que o Firewall deve substituir as melhores práticas de desenvolvimento para proteção contra injeção de SQL, como usar consultas parametrizadas ou nunca confiar na entrada do usuário, mas também sabemos por experiência própria que nenhum desenvolvedor é perfeito. Nenhuma base de código é impecável, e erros honestos acontecem o tempo todo.

Pense no Firewall como um hotfix global para injeção SQL. Ao contrário de regexes desenvolvidas sob medida, WAFs que induzem latência ou agentes de segurança complexos que custam caro, ele faz esse trabalho excepcionalmente bem e com impacto insignificante — inteiramente de graça.

Se você gostou do que viu, confira nosso roadmap e dê uma estrela ao nosso repositório GitHub (https://github.com/AikidoSec/firewall-node). ⭐

Compartilhar:

https://www.aikido.dev/blog/sensing-and-blocking-javascript-sql-injection-attacks-aikido-firewall

Assine para receber notícias sobre ameaças.

Comece hoje, gratuitamente.

Comece Gratuitamente
Não é necessário cc

Fique seguro agora

Proteja seu código, Cloud e runtime em um único sistema centralizado.
Encontre e corrija vulnerabilidades rapidamente de forma automática.

Não é necessário cartão de crédito | Resultados da varredura em 32 segundos.