"Página inicial do autor": Shibie Sanri wyx
"Sobre o autor": CSDN top100, especialista em blog Alibaba Cloud, especialista em compartilhamento de nuvem Huawei, criador de alta qualidade na área de segurança de rede
"Coluna recomendada": Amigos interessados em segurança de rede podem siga a coluna "Segurança de rede do iniciante ao mestre"
Pré-compilar para evitar injeção de SQL
Primeiro, vamos entender brevemente o processo de injeção de SQL.
Por exemplo, uma função de consulta consulta o nome de usuário e a senha com base no ID inserido pelo usuário.
A instrução SQL em segundo plano é assim
select *from user where id='1'
Se enviarmos a carga útil nos parâmetros
https://127.0.0.1/Less-1/?id=-1' union select 1, 2, user()-- a
O SQL de fundo será dividido assim (nota importante aqui: a estrutura da sintaxe do SQL foi alterada)
select *from user where id='-1' union select 1, 2, user()-- a'
Ajude-nos a encontrar a conta do administrador do banco de dados que causou a injeção de SQL.
A partir do processo de injeção, podemos descobrir que o núcleo da injeção SQL é que os parâmetros inseridos pelo usuário alteram a estrutura sintática do SQL.
A pré-compilação pode impedir que a estrutura da sintaxe seja alterada. Antes de falar sobre pré-compilação, devemos primeiro entender o processo de execução do SQL.
1. Processo de execução SQL
Tomando o MySQL como exemplo, quando o banco de dados executa uma instrução SQL, ele precisa passar por 7 etapas:
- Análise lexical: decomponha a instrução SQL em tokens (palavras-chave, identificadores, operadores) e, em seguida, classifique e analise os tokens para gerar estruturas de dados correspondentes.
- Análise de sintaxe: Verifique se a sintaxe está correta de acordo com as regras de detecção de sintaxe SQL e forme uma árvore sintática.
- Análise semântica: percorra a árvore sintática, determine informações como tabelas e colunas e verifique a exatidão da semântica.
- Processamento de otimização: Use o otimizador para processar e otimizar instruções SQL, como planos de execução, índices, etc.
- Plano de execução: Use o gerador de plano de execução para gerar o plano de execução da instrução SQL, como como acessar dados, como usar índices, etc.
- Execução do mecanismo: envia o plano de execução ao mecanismo de banco de dados correspondente para processamento. O plano de execução é traduzido em instruções de operação subjacentes para realizar varredura de dados, pesquisa de índice, classificação, agrupamento e outras operações.
- Dados de retorno: Retorna resultados de execução ao cliente, como conjuntos de resultados de consulta ou resultados de operação.
Aqui, entendemos aproximadamente o processo de execução em duas etapas, a saber: primeiro compilar a estrutura da sintaxe SQL ( 1~3步
) e, em seguida, executar a instrução SQL ( 4~7步
).
Em circunstâncias normais, os parâmetros inseridos pelo usuário participarão diretamente na compilação da sintaxe SQL, enquanto a pré-compilação primeiro constrói uma árvore sintática, determina a estrutura da sintaxe SQL e depois une os parâmetros do usuário.
2. Princípio da pré-compilação
O objetivo original da pré-compilação é melhorar a capacidade de reutilização do código, pois existem muitos SQLs que possuem apenas valores de parâmetros diferentes (exatamente o mesmo SQL será consultado no cache), como:
select * from user where id='1'
select * from user where id='2'
As árvores de sintaxe desses SQLs são as mesmas, mas precisam ser compiladas repetidamente todas as vezes, o que é uma perda de tempo.
A pré-compilação pode modelar a instrução SQL e substituir a posição do valor por um espaço reservado.Desta forma, o banco de dados compilará a estrutura de sintaxe SQL antecipadamente e depois passará o valor para execução quando for realmente chamado, eliminando a necessidade de repetir construir uma árvore de sintaxe.
select * from user where id={占位符}
A julgar pela captura de pacotes, a instrução SQL é primeiro pré-compilada (instrução Prepare) e os valores dos parâmetros são primeiro substituídos por espaços reservados. Ao executar (Execute Statement), passe os parâmetros.
Os parâmetros passados pelo usuário não participam da construção da árvore sintática, portanto a estrutura sintática do SQL não pode ser alterada, evitando assim a injeção.
Extensões:
O PDO (PHP Data Object) do PHP é uma interface unificada para operar vários bancos de dados e fornece dois mecanismos de pré-compilação: pré-compilação local e pré-compilação simulada.
A pré-compilação local refere-se à pré-compilação do próprio banco de dados, que também é o método de pré-compilação que mencionamos aqui.
A pré-compilação simulada é usada para bancos de dados que não suportam pré-compilação.Essencialmente, a entrada do usuário é traduzida no nível inferior e, em seguida, a instrução SQL é emendada e, em seguida, a instrução SQL completa é enviada ao banco de dados para execução.
Os parâmetros traduzidos serão tratados apenas como strings e não podem participar da compilação SQL (antes do PHP 5.3.6, a tradução do conjunto de caracteres de byte único era usada e existia a injeção de byte único). A configuração correta do conjunto de caracteres também pode impedir a injeção de SQL.
3. Pré-compilar para evitar injeção de SQL
Tomemos como exemplo MyBatis (estrutura de camada de persistência semiautomática). #{id}
Ao passar parâmetros neste formato, o SQL será primeiro passado para o banco de dados para pré-compilação. Quando chamados, os espaços reservados serão substituídos por parâmetros e depois executados.
<select id="getUser" resultType="Blog" parameterType=”int”>
SELECT *
FROM user
WHERE id=#{
id}
</select>
No entanto, alguns SQL requerem o uso de nomes de tabelas e colunas dinâmicas. Nesse caso, a pré-compilação não pode ser usada e precisa ser substituída. Dessa forma, os parâmetros #{id}
participarão ${id}
diretamente da compilação SQL e não poderão impedir a injeção de SQL. Neste momento , os parâmetros deverão ser filtrados manualmente.
Dica: A pré-compilação da estrutura MyBatis é a classe PreparedStatement em JDBC e seu objeto contém instruções SQL compiladas.
Usando a função de pré-compilação do MySQL em PHP:
1) Defina a instrução SQL pré-compilada e os parâmetros são representados por espaços reservados?
$sql = "SELECT * FROM user WHERE id= ? ";
2) Crie objetos de pré-processamento
$mysqli_stmt = $mysqli->prepare($sql);
3) Vincular parâmetros
$mysqli_stmt->bind_param('i', $id);
4) Vincule o conjunto de resultados
$mysqli_stmt->bind_result($username);
5) Execução
$mysqli_stmt->execute();
4. Limitações da pré-compilação
O mecanismo de pré-compilação consiste em compilar primeiro e depois passar o valor.Os parâmetros passados pelo usuário não podem alterar a estrutura da sintaxe SQL, o que resolve fundamentalmente o problema de injeção de SQL.
Mas nem todos os parâmetros podem usar pré-compilação, como o cenário de nomes de tabelas dinâmicas e nomes de colunas. Porque durante a análise semântica, a árvore de sintaxe será analisada para verificar se o nome da tabela e o nome da coluna existem, portanto, o nome da tabela e o nome da coluna não podem ser substituído por espaços reservados. Não há como usar a pré-compilação.
Da mesma forma, ASC/DESC em cenários de classificação também requer transferência dinâmica de parâmetros e a pré-compilação não pode ser usada.