A injeção SQL é um vetor de ataque simples que ainda é muito comum hoje. O motivo disso não é outro do que não ter patch para o. Por que você diz isso? Vamos pegar o JAVA como exemplo para ilustrar:
Suponha que exista uma tabela assim no banco de dados:
Depois, use a tabela de ações do JDBC:
O código acima é frequentemente usado por alguns desenvolvedores. Imagine uma situação em que o parâmetro userId de entrada é "3; usuário de tabela de drop; A instrução SQL executada é a seguinte:
Após a compilação e execução do banco de dados, a tabela de usuário é excluída. Voilà, um simples ataque de injeção SQL entra em ação! Isso porque o código acima não está de acordo com as especificações de programação.
Quando programamos de acordo com a especificação, a injeção SQL é inexistente. Isso também é verdadeA primeira forma de evitar a injeção SQL: instruções pré-compiladas, o código é o seguinte:
Por que a injeção SQL não existe no código acima? Como a instrução pré-compilada é usada, a instrução pré-compilada definirá "select name from user where id= ?" A instrução é compilada antecipadamente para que só precise ser substituída pelos parâmetros de entrada quando executada? Os marcadores estão ok. No primeiro caso não compatível, o programa escreve uma instrução SQL e depois compila com o conteúdo passado pelo usuário, que é exatamente o problema.
Além de usar instruções pré-compiladas, há uma segunda opçãoManeiras de evitar ataques por injeção SQL: Procedimentos armazenados。 Um procedimento armazenado é um conjunto de instruções SQL que executam uma função específica, compiladas e armazenadas em um banco de dados, e o usuário pode executá-lo chamando um procedimento armazenado e fornecendo um parâmetro (se o procedimento armazenado tiver parâmetros), o que também pode evitar ataques de injeção SQL
O procedimento armazenado correspondente no código acima é o seguinte:
Claro, os usuários também podem fazer verificação de caracteres na interface, o que também é uma forma de evitar a injeção SQL: por exemplo, para o parâmetro userId acima, o usuário verificará um ponto e vírgula e um erro será exibido. No entanto, a razão mais fundamental é que os ataques de injeção SQL existem porque os aplicativos não usam o privilégio mínimo ao acessar bancos de dados. Parece que todo mundo tem usado a conta raiz para acessar o banco de dados.
Então, como o MyBatis evita ataques de injeção SQL? Ou pegue o usuário da tabela acima como exemplo: Vamos supor que o arquivo mapper seja:
Os arquivos Java correspondentes são:
Você pode ver que o parâmetro de entrada é userId do tipo String, quando passamos userId="34; usuário de tabela de drop; Depois disso, a declaração impressa diz:
Independentemente do userID digitado, a declaração SQL dele é assim. Isso se deve ao fato de que mybatis utiliza instruções pré-compiladas na implementação subjacente. Quando o banco de dados executa essa instrução, ele usa diretamente a instrução pré-compilada e então substitui o placeholder pelo userId? Vai correr. Trocar os marcadores de lugar primeiro? O processo de compilação é realizado, então não há espaço para a injeção SQL sobreviver.
Então, como o MyBatis faz pré-compilação SQL? Na verdade, a classe PreparedStatement é usada na parte inferior do framework. A classe PreparedStaement não apenas evita a injeção SQL, mas também economiza (N-1) tempo de compilação quando a mesma instrução SQL é executada N vezes, melhorando assim a eficiência.
Se você mudar a afirmação acima para:
Quando inserimos userId="34; usuário de tabela de drop; Depois disso, a declaração impressa diz:
No momento, o mybatis não usa instruções pré-compiladas, ele costura as strings primeiro e depois realiza a compilação, que é exatamente como a injeção SQL entra em efeito.
Portanto, ao escrever instruções de mapeamento mybatis, tente usar o formato "#{xxx}". Se você precisa usar parâmetros como "${xxx}", precisa filtrá-los manualmente para evitar ataques de injeção SQL.
|