O que é injeção de SQL e como impedir em aplicativos PHP?

Então você acha que seu banco de dados SQL tem desempenho e é seguro contra destruição instantânea? Bem, injeção SQL discorda!


Sim, estamos falando da destruição instantânea, porque não quero abrir este artigo com a terminologia comum de “aumentar a segurança” e “impedir o acesso malicioso”. A injeção de SQL é um truque tão antigo do livro que todos, todos os desenvolvedores, sabem muito bem sobre ela e sabem bem como evitá-la. Exceto naquele momento ímpar em que eles escorregam, e os resultados podem ser nada menos que desastrosos.

Se você já sabe o que é injeção SQL, sinta-se à vontade para pular para a segunda metade do artigo. Mas para aqueles que estão surgindo no campo do desenvolvimento da Web e sonham em assumir funções mais seniores, é necessário fazer uma introdução.

O que é injeção SQL?

A chave para entender o SQL Injection está em seu nome: SQL + Injection. A palavra “injeção” aqui não tem nenhuma conotação médica, mas é o uso do verbo “injetar”. Juntas, essas duas palavras transmitem a idéia de colocar SQL em um aplicativo da web.

Colocando SQL em um aplicativo Web. . . hmmm. . . Não é isso que estamos fazendo? Sim, mas não queremos que um invasor direcione nosso banco de dados. Vamos entender isso com a ajuda de um exemplo.

Digamos que você esteja criando um site PHP típico para uma loja de comércio eletrônico local, por isso, decida adicionar um formulário de contato como este:

Seu nome

Sua mensagem

E vamos assumir que o arquivo send_message.php armazena tudo em um banco de dados para que os proprietários da loja possam ler as mensagens do usuário posteriormente. Pode ter algum código como este:

<?php

$ name = $ _POST [‘nome’];
$ message = $ _POST [‘mensagem’];

// verifica se este usuário já possui uma mensagem
mysqli_query ($ conn, "SELECT * das mensagens em que name = $ name");

// Outro código aqui

Então, você está primeiro tentando verificar se esse usuário já possui uma mensagem não lida. A consulta SELECT * de mensagens em que name = $ name parece bastante simples, certo?

ERRADO!

Em nossa inocência, abrimos as portas para a destruição instantânea de nosso banco de dados. Para que isso aconteça, o invasor precisa atender às seguintes condições:

  • O aplicativo está sendo executado em um banco de dados SQL (hoje, quase todos os aplicativos estão)
  • A conexão atual do banco de dados possui permissões de “edição” e “exclusão” no banco de dados
  • Os nomes das tabelas importantes podem ser adivinhados

O terceiro ponto significa que agora que o invasor sabe que você está executando uma loja de comércio eletrônico, é provável que você armazene os dados do pedido em uma tabela de pedidos. Armado com tudo isso, tudo o que o invasor precisa fazer é fornecer isso como seu nome:

Joe; ordens truncadas ;? Sim senhor! Vamos ver o que a consulta se tornará quando for executada pelo script PHP:

SELECT * FROM messages ONDE name = Joe; ordens truncadas;

Ok, a primeira parte da consulta possui um erro de sintaxe (sem aspas, “Joe”), mas o ponto e vírgula força o mecanismo MySQL a começar a interpretar um novo: pedidos truncados. Assim, de uma só vez, todo o histórico de pedidos desapareceu!

Agora que você sabe como o SQL Injection funciona, é hora de ver como interrompê-lo. As duas condições que precisam ser atendidas para uma injeção SQL bem-sucedida são:

  1. O script PHP deve ter privilégios de modificação / exclusão no banco de dados. Acho que isso vale para todos os aplicativos e você não poderá torná-los somente leitura. �� E adivinhe, mesmo se removermos todos os privilégios de modificação, a injeção de SQL ainda pode permitir que alguém execute consultas SELECT e visualize todo o banco de dados, incluindo dados confidenciais. Em outras palavras, reduzir o nível de acesso ao banco de dados não funciona, e seu aplicativo precisa mesmo assim.
  2. A entrada do usuário está sendo processada. A única maneira de a injeção de SQL funcionar é quando você aceita dados de usuários. Mais uma vez, não é prático interromper todas as entradas do seu aplicativo apenas porque você está preocupado com a injeção de SQL.

Impedindo a injeção de SQL em PHP

Agora, como as conexões com o banco de dados, as consultas e as entradas do usuário fazem parte da vida, como podemos evitar a injeção de SQL? Felizmente, é bem simples e há duas maneiras de fazer isso: 1) higienizar a entrada do usuário e 2) usar instruções preparadas.

Limpar a entrada do usuário

Se você estiver usando uma versão mais antiga do PHP (5.5 ou inferior, e isso acontece muito em hospedagem compartilhada), é aconselhável executar toda a entrada do usuário por meio de uma função chamada mysql_real_escape_string (). Basicamente, o que ele remove todos os caracteres especiais em uma string, para que eles percam o significado quando usados ​​pelo banco de dados.

Por exemplo, se você possui uma string como eu, o caractere de aspas simples (‘) pode ser usado por um invasor para manipular a consulta do banco de dados que está sendo criada e causar uma injeção de SQL. Executá-lo através de mysql_real_escape_string () produz Eu sou uma string, que adiciona uma barra invertida à aspas simples, escapando-a. Como resultado, a cadeia inteira agora é passada como uma cadeia inofensiva para o banco de dados, em vez de poder participar da manipulação de consultas.

Há uma desvantagem nessa abordagem: é uma técnica muito, muito antiga, que acompanha as formas mais antigas de acesso ao banco de dados em PHP. A partir do PHP 7, essa função não existe mais, o que nos leva à nossa próxima solução.

Use declarações preparadas

As instruções preparadas são uma maneira de fazer consultas ao banco de dados com mais segurança e confiabilidade. A ideia é que, em vez de enviar a consulta bruta ao banco de dados, primeiro digamos ao banco de dados a estrutura da consulta que enviaremos. É isso que queremos dizer com “preparar” uma declaração. Depois que uma instrução é preparada, passamos as informações como entradas parametrizadas para que o banco de dados possa “preencher as lacunas” inserindo as entradas na estrutura de consulta que enviamos anteriormente. Isso retira qualquer poder especial que as entradas possam ter, fazendo com que sejam tratadas como meras variáveis ​​(ou cargas úteis, se você desejar) em todo o processo. Veja como são as declarações preparadas:

<?php
$ servername = "localhost";
$ nome de usuário = "nome do usuário";
$ password = "senha";
$ dbname = "myDB";

// Criar conexão
$ conn = novo mysqli ($ servername, $ nome de usuário, $ senha, $ dbname);

// Verifique a conexão
if ($ conn->connect_error) {
morrer("Falha na conexão: " . $ conn->connect_error);
}

// preparar e vincular
$ stmt = $ conn->preparar("INSERIR EM MyGuests (nome, sobrenome, email) VALORES (?,?,?)");
$ stmt->bind_param ("sss", $ nome, $ sobrenome, $ email);

// define parâmetros e executa
$ firstname = "John";
$ lastname = "Corça";
$ email = "[protegido por email]";
$ stmt->executar();

$ firstname = "Maria";
$ lastname = "Moe";
$ email = "[protegido por email]";
$ stmt->executar();

$ firstname = "Julie";
$ lastname = "Dooley";
$ email = "[protegido por email]";
$ stmt->executar();

eco "Novos registros criados com sucesso";

$ stmt->Fechar();
$ conn->Fechar();
?>

Sei que o processo parece desnecessariamente complexo se você é novo nas declarações preparadas, mas o conceito vale o esforço. Aqui está uma boa introdução.

Para aqueles que já estão familiarizados com a extensão DOP do PHP e a usam para criar instruções preparadas, tenho um pequeno conselho.

Aviso: Tenha cuidado ao configurar o DOP

Ao usar o PDO para acesso ao banco de dados, podemos ser sugados por uma falsa sensação de segurança. “Ah, bem, eu estou usando DOP. Agora não preciso pensar em mais nada “- é assim que geralmente pensamos. É verdade que a DOP (ou instruções preparadas para MySQLi) é suficiente para evitar todos os tipos de ataques de injeção de SQL, mas você deve ter cuidado ao configurá-lo. É comum apenas copiar e colar código de tutoriais ou de seus projetos anteriores e seguir em frente, mas essa configuração pode desfazer tudo:

$ dbConnection->setAttribute (PDO :: ATTR_EMULATE_PREPARES, true);

O que essa configuração faz é dizer ao PDO para emular instruções preparadas, em vez de realmente usar o recurso de instruções preparadas do banco de dados. Consequentemente, o PHP envia cadeias de consulta simples ao banco de dados, mesmo que seu código pareça estar criando instruções preparadas e definindo parâmetros e tudo isso. Em outras palavras, você é tão vulnerável à injeção de SQL quanto antes. ��

A solução é simples: verifique se essa emulação está definida como false.

$ dbConnection->setAttribute (PDO :: ATTR_EMULATE_PREPARES, false);

Agora, o script PHP é forçado a usar instruções preparadas no nível do banco de dados, impedindo todos os tipos de injeção de SQL.

Impedindo o uso do WAF

Você sabe que também pode proteger aplicativos da Web da injeção de SQL usando WAF (firewall de aplicativo da Web)?

Bem, não apenas a injeção de SQL, mas muitas outras vulnerabilidades da camada 7, como scripts entre sites, autenticação interrompida, falsificação entre sites, exposição de dados etc. Você pode usar o host próprio como o Mod Security ou baseado em nuvem, como a seguir.

Injeção de SQL e estruturas PHP modernas

A injeção de SQL é tão comum, tão fácil, tão frustrante e tão perigosa que todas as estruturas da Web PHP modernas são incorporadas com contramedidas. No WordPress, por exemplo, temos o $ wpdb->prepare (), enquanto que se você estiver usando uma estrutura MVC, ele fará todo o trabalho sujo para você e você nem precisará pensar em impedir a injeção de SQL. É um pouco chato que no WordPress você tenha que preparar declarações explicitamente, mas ei, é sobre o WordPress que estamos falando. ��

De qualquer forma, meu argumento é que a raça moderna de desenvolvedores da web não precisa pensar em injeção de SQL e, como resultado, nem sequer estão cientes da possibilidade. Dessa forma, mesmo que eles deixem um backdoor aberto no aplicativo (talvez seja um parâmetro de consulta $ _GET e os velhos hábitos de disparar uma consulta suja), os resultados podem ser catastróficos. Por isso, é sempre melhor reservar um tempo para aprofundar-se nas fundações.

Conclusão

A injeção de SQL é um ataque muito desagradável a um aplicativo da Web, mas é facilmente evitada. Como vimos neste artigo, ter cuidado ao processar a entrada do usuário (a propósito, SQL Injection não é a única ameaça que o tratamento da entrada do usuário traz) e consultar o banco de dados é tudo o que existe. Dito isto, nem sempre estamos trabalhando na segurança de uma estrutura da Web, por isso é melhor estar ciente desse tipo de ataque e não cair nele..

Jeffrey Wilson Administrator
Sorry! The Author has not filled his profile.
follow me
    Like this post? Please share to your friends:
    Adblock
    detector
    map