Aikido

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

Mackenzie JacksonMackenzie 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

Aikido lançou recentemente o Firewall, um mecanismo de segurança gratuito e de código aberto que protege você de forma autónoma 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 que acompanha o repositório de código aberto para mostrar como Aikido funciona. Também será necessárioo Docker/Docker Compose para implementar uma base 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 o Docker para implementar uma base de dados MySQL local na porta 27015. Este ficheiro docker-compose.yml também cria contentores s3mock, MongoDB e PostgreSQL, pois foi criado para ajudar a 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ções SQL em JavaScript com Aikido

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 ainda não tem uma 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 Aikido para ler o 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)

Aikido instrui-o sobre como instalar e implementar Aikido . Como estamos a usar o aplicativo de exemplo, esse trabalho já está feito para si, mas é uma referência útil sobre como você poderia implementar o nosso mecanismo de segurança de código aberto em todos os seus aplicativos Node.js que possam estar vulneráveis a ataques de injeção SQL em JavaScript.

Digite a legenda (opcional)

Clique no Gerar Token para criar um token que permite Aikido passar com segurança informações sobre ataques de injeção SQL bloqueados para a plataforma 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 invocar novamente o ataque de injeção SQL incluído. Desta vez, Aikido bloqueá-lo no navegador, enviar os dados para os registos do seu servidor web local e gerar um novo evento. Clique nele para ver detalhes completos sobre a tentativa de injeção SQL, incluindo a carga útil e onde a sua aplicação 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 permanentemente as suas aplicações contra ataques de injeção SQL em JavaScript, tanto críticos como ainda não identificados, Aikido oferece um bloqueio abrangente e uma observabilidade sofisticada que o mantém informado sobre as fontes de ataque, cargas úteis comuns e potenciais pontos fracos.

O que vem a seguir?

Pode instalar e implementar Aikido em todas as suas aplicações baseadas em Node.js gratuitamente. O nosso mecanismo de segurança incorporado de código aberto protege a sua infraestrutura e os dados dos utilizadores contra ataques de injeção SQL em JavaScript, injeção de comandos, poluição de protótipos, traversal de caminhos 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). ⭐

4.7/5

Proteja seu software agora

Comece Gratuitamente
Não é necessário cc
Agendar uma demonstração
Seus dados não serão compartilhados · Acesso somente leitura · Não é necessário cartão de crédito

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.