A injeção de SQL é um método de ataque muito simples, mas ainda é muito comum até hoje. O motivo é nada mais do que: nenhum patch para estúpido. Por que você diz isso? Vamos tomar Java como exemplo para ilustrar:
Suponha que haja uma tabela como esta no banco de dados:
Usuário da tabela (ID Varchar (20) Primária Chave, Nome Varchar (20), Age Varchar (20));
Em seguida, use o JDBC para operar a tabela:
private string getNameByUserID (string userID) {conexão conn = getConn (); // obtenha a string de conexão sql = "Selecione o nome do usuário em que id =" + userID; Preparado PSTMT = Conn.Preparestatement (SQL); ResultSet rs = pstmt.executeUpdate (); ......}O código acima é frequentemente usado por alguns desenvolvedores. Imagine essa situação, quando o parâmetro UserID aprovado é "3; Drop Table User;", a instrução SQL executada é a seguinte:
Selecione o nome do usuário onde id = 3; soltar o usuário da tabela;
Depois que o banco de dados é compilado e executado, a tabela de usuários é excluída. Olha, um simples ataque de injeção de SQL está em vigor! Isso ocorre porque o código acima não cumpre as especificações de programação.
A injeção de SQL não existe quando programamos de acordo com as especificações. Esta também é a primeira maneira de evitar a injeção de SQL: declarações pré -compiladas, o código é o seguinte:
Conexão Conn = getConn (); // Obter conexão string sql = "Selecione o nome do usuário onde id =?"; Preparado PSTMT = Conn.Preparestatement (SQL); Pstmt.SetString (1, UserID); ResultSet rs = pstmt.executeUpdate (); ....
Por que a injeção de SQL não existe no código acima? Como as declarações pré -compiladas são usadas, a instrução pré -compilada compilará o "Selecionar nome do usuário onde id =?" Declaração com antecedência ao executar, portanto, ao executar, você só precisa substituí -lo pelos parâmetros passados? Espaço reservado. Para o primeiro caso que não atende às especificações, o programa criará instruções SQL e as compilam com o conteúdo passado pelo usuário. Este é exatamente o problema.
Além de usar declarações pré -compiladas, há uma segunda maneira de evitar ataques de injeção de SQL: procedimentos armazenados. O procedimento armazenado é um conjunto de instruções SQL que concluem funções específicas. Após a compilação, é armazenado no banco de dados. Os usuários podem executá -lo chamando procedimentos armazenados e fornecendo parâmetros (se o procedimento armazenado tiver parâmetros) e também poderá evitar ataques de injeção de SQL.
Conexão conn = getConn (); stmt = Conn.Preparecall ("{chamado name_from_user (?,?)}"); stmt.setInt (1,2); stmt.RegisterOutParameter (2, tipos.varchar); stmt.execute (); Nome da sequência = stmt.getString (2);Os procedimentos armazenados correspondentes no código acima são os seguintes:
use usuário; delimiter // Crie procedimento name_from_user (em user_id int, out user_name varchar (20)) inicie selecione o nome em user_name do usuário onde id = user_id; end // delimiter;
Obviamente, os usuários também podem fazer a verificação de caracteres no front end, que também é uma maneira de evitar a injeção de SQL: por exemplo, para o parâmetro UserID acima, o usuário solicitará um erro ao verificar se o semicolon está incluído.
No entanto, pelo motivo mais fundamental, o ataque de injeção SQL existe porque o aplicativo não usa as permissões mínimas ao acessar o banco de dados. Acho que sim, parece que todos estão usando a conta raiz para acessar o banco de dados.
Então, como o Mybatis evita ataques de injeção de SQL? Vamos usar o usuário da tabela acima como exemplo:
Suponha que o arquivo de mapeador seja:
<select id = "getNameByUserId" resultype = "string"> selecione o nome do usuário onde id = #{userId} </leclect>O arquivo java correspondente é:
interface pública UserMApper {String getNameByUserID (@param ("userId") string userID); }Você pode ver que o parâmetro de entrada é o UserID do tipo String. Quando passamos pelo userID = "34; soltar o usuário da tabela;" A declaração impressa é a seguinte:
Selecione o nome do usuário onde id =?
Não importa o que o UserID seja inserido, suas instruções SQL são assim. Isso se deve ao uso de declaraçõ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 substitui o espaço reservado pelo UserID aprovado? Apenas vá para correr. Não existe para substituir o espaço reservado primeiro? O processo de compilação é realizado, portanto, não há espaço para sobrevivência para a injeção de SQL.
Então, como o mybatis alcança a pré-compilação do SQL? De fato, a estrutura está usando a classe preparada. A classe Preparedstaement não apenas evita a injeção de SQL, porque foi pré -compilada. Quando a mesma instrução SQL é executada n vezes, ela economiza tempo de compilação (N-1), melhorando assim a eficiência.
Se você alterar a declaração acima para:
<select id = "getNameByUserID" resultype = "string"> selecione o nome do usuário onde id = $ {userId} </leclect> Quando entramos userId="34;drop table user;" , a declaração impressa é assim:
Selecione o nome do usuário em que id = 34; soltar o usuário da tabela;
Neste momento, o Mybatis não usa declarações pré -compiladas. Primeiro, ele executará a costura de string e depois a compilação. Esse processo é o processo de injeção de SQL em vigor.
Portanto, ao escrever declarações de mapeamento mybatis, tente usar o formato "#{xxx}". Se você precisar usar parâmetros como "$ {xxx}", deve fazer um bom trabalho de filtragem para evitar ataques de injeção de SQL.
Resumir
O exposto acima é uma explicação detalhada do método de impedir a injeção de SQL por Mybatis apresentada a você. Espero que seja útil para você. Se você tiver alguma dúvida, deixe -me uma mensagem e o editor responderá a você a tempo. Muito obrigado pelo seu apoio ao site wulin.com!