La inyección SQL es un vector de ataque sencillo que sigue siendo muy común hoy en día. La razón de esto no es otra que no tener parche para lo estúpido. ¿Por qué dices esto? Tomemos JAVA como ejemplo para ilustrarlo:
Supongamos que existe una tabla así en la base de datos:
Luego usa la tabla de acciones de JDBC:
El código anterior es utilizado a menudo por algunos desarrolladores. Imagina una situación en la que el parámetro de usuarioId entrante es "3; usuario de la tabla de desecho; La instrucción SQL ejecutada es la siguiente:
Después de compilar y ejecutar la base de datos, la tabla de usuario se elimina. ¡Voilà, un simple ataque de inyección SQL entra en marcha! Esto se debe a que el código anterior no cumple con las especificaciones de programación.
Cuando programamos según la especificación, la inyección SQL es inexistente. Esto también es asíLa primera forma de evitar la inyección SQL: sentencias precompiladas, el código es el siguiente:
¿Por qué no existe la inyección SQL en el código anterior? Como se utiliza la sentencia precompilada, la sentencia precompilada establecerá "select name from user where id= ?" ¿La instrucción se compila de antemano para que solo necesite ser reemplazada por los parámetros entrantes cuando se ejecute? Los marcadores de posición están bien. En el primer caso de no conforme, el programa escribe una sentencia SQL y luego la compila con el contenido que transmite el usuario, que es precisamente el problema.
Además de usar sentencias precompiladas, hay una segunda opciónFormas de evitar ataques de inyección SQL: Procedimientos almacenados。 Un procedimiento almacenado es un conjunto de sentencias SQL que realizan una función específica, compiladas y almacenadas en una base de datos, y el usuario puede ejecutarlo llamando a un procedimiento almacenado y proporcionando un parámetro (si el procedimiento almacenado tiene parámetros), lo que también puede evitar ataques de inyección SQL
El procedimiento almacenado correspondiente en el código anterior es el siguiente:
Por supuesto, los usuarios también pueden hacer comprobación de caracteres en el frontend, lo que es una forma de evitar la inyección SQL: por ejemplo, para el parámetro userId anterior, el usuario comprobará si hay punto y coma y se mostrará un error. Sin embargo, la razón más fundamental es que existen ataques de inyección SQL porque las aplicaciones no usan el mínimo privilegio al acceder a bases de datos. Parece que todo el mundo ha estado usando la cuenta raíz para acceder a la base de datos.
¿Cómo evita MyBatis los ataques de inyección SQL? O toma como ejemplo al usuario de la tabla anterior: Supongamos que el archivo mapper es:
Los archivos Java correspondientes son:
Puedes ver que el parámetro de entrada es userId de tipo String, cuando pasamos userId="34; usuario de la tabla de desecho; Después de eso, la declaración impresa dice:
Independientemente del userID introducido, su declaración SQL es así. Esto se debe a que mybatis utiliza sentencias precompiladas en la implementación subyacente. Cuando la base de datos ejecuta esa sentencia, usa directamente la instrucción precompilada y luego reemplaza el marcador de posición por el userId. Solo vete a correr. ¿Cambiar primero los marcadores de posición? El proceso de compilación se lleva a cabo, por lo que no hay margen para que la inyección SQL sobreviva.
¿Entonces cómo hace MyBatis la precompilación SQL? De hecho, la clase PreparedStatement se utiliza en la parte inferior del marco. La clase PreparedStaement no solo evita la inyección SQL, sino que también ahorra (N-1) tiempo de compilación cuando la misma sentencia SQL se ejecuta N veces, mejorando así la eficiencia.
Si cambias la afirmación anterior a:
Cuando introducimos userId="34; usuario de la tabla de desecho; Después de eso, la declaración impresa dice:
Por ahora, mybatis no utiliza sentencias precompiladas, primero unirá cadenas y luego realizará la compilación, que es exactamente como entra en vigor la inyección SQL.
Por lo tanto, al escribir sentencias de mapeo mybatis, intenta usar el formato "#{xxx}". Si tienes que usar parámetros como "${xxx}", tienes que filtrarlos manualmente para evitar ataques de inyección SQL.
|