La inyección de SQL es un método de ataque muy simple, pero todavía es muy común para el día de hoy. La razón no es más que: ningún parche para estúpido. ¿Por qué dices eso? Tomemos a Java como ejemplo para ilustrar:
Supongamos que hay una tabla como esta en la base de datos:
Usuario de tabla (ID VARCHAR (20) Clave principal, nombre Varchar (20), Age Varchar (20));
Luego use JDBC para operar la tabla:
String private getNameByUserId (String UserId) {Connection conn = getConn (); // get Connection String sql = "Seleccione el nombre del usuario donde id =" + userId; Preparado PSTMT = Conn.PrepareStatement (SQL); ResultSet rs = pstmt.executeUpdate (); ......}El código anterior es a menudo utilizado por algunos desarrolladores. Imagine esta situación, cuando el parámetro de usuario pasado es "3; el usuario de la tabla de caída", la instrucción SQL ejecutada es la siguiente:
Seleccione el nombre del usuario donde id = 3; Usuario de la tabla de caída;
Después de compilar y ejecutar la base de datos, se elimina la tabla de usuario. ¡Mira, un simple ataque de inyección SQL está vigente! Esto se debe a que el código anterior no cumple con las especificaciones de programación.
La inyección SQL no existe cuando programamos de acuerdo con las especificaciones. Esta es también la primera forma de evitar la inyección de SQL: declaraciones precompiladas, el código es el siguiente:
Connection conn = getConn (); // get Connection String sql = "Seleccione el nombre del usuario donde id =?"; Preparado PSTMT = Conn.PrepareStatement (SQL); PSTMT.SetString (1, UserId); ResultSet rs = pstmt.executeUpdate (); ....
¿Por qué no existe la inyección de SQL en el código anterior? Debido a que se utilizan declaraciones precompiladas, la declaración precompilada compilará el "seleccionar el nombre del usuario donde id =?" Declaración de anticipación al ejecutar, por lo que al ejecutar, ¿solo necesita reemplazarla con los parámetros aprobados? Marcador de posición. Para el primer caso que no cumple con las especificaciones, el programa creará declaraciones SQL y luego las compilará con el contenido aprobado por el usuario. Este es exactamente el problema.
Además de usar declaraciones precompiladas, hay una segunda forma de evitar ataques de inyección SQL: procedimientos almacenados. El procedimiento almacenado es un conjunto de declaraciones SQL que completan funciones específicas. Después de la compilación, se almacena en la base de datos. Los usuarios pueden ejecutarlo llamando a procedimientos almacenados y dando parámetros (si el procedimiento almacenado tiene parámetros), y también puede evitar ataques de inyección SQL.
Conexión conn = getConn (); stmt = conn.prepareCall ("{llame name_from_user (?,?)}"); stmt.setInt (1,2); stmt.RegisterOutParameter (2, tipos.varchar); stmt.execute (); Name de cadena = stmt.getString (2);Los procedimientos almacenados correspondientes en el código anterior son los siguientes:
usar usuario; delimitador // Crear procedimiento name_from_user (en user_id int, out user_name varchar (20)) Comience Seleccionar nombre en user_name desde user where id = user_id; final // delimitador;
Por supuesto, los usuarios también pueden verificar el carácter en la parte delantera, lo cual también es una forma de evitar la inyección de SQL: por ejemplo, para el parámetro de usuario de usuario anterior, el usuario solicitará un error al verificar que se incluye el punto y coma.
Sin embargo, por la razón más fundamental, el ataque de inyección SQL existe porque la aplicación no utiliza los permisos mínimos al acceder a la base de datos. Creo que sí, parece que todos han estado usando la cuenta raíz para acceder a la base de datos.
Entonces, ¿cómo evita mybatis ataques de inyección SQL? Usemos el usuario de la tabla anterior como ejemplo:
Suponga que el archivo mapper es:
<select id = "getNameByUserId" resultType = "String"> Seleccione Nombre del usuario Where id = #{userId} </select>El archivo Java correspondiente es:
interfaz pública usermapper {string getNameByUserId (@param ("userId") string userId); }Puede ver que el parámetro de entrada es ID de usuario del tipo de cadena. Cuando pasamos userId = "34; caída del usuario de la tabla;" La declaración impresa es la siguiente:
Seleccione el nombre del usuario donde id =?
No importa a qué se ingrese el INSERVADO, sus declaraciones SQL son como esta. Esto se debe al uso de declaraciones precompiladas en la implementación subyacente. Cuando la base de datos ejecuta esta declaración, usa directamente la declaración precompilada y luego reemplaza al marcador de posición con el ID de usuario aprobado? Solo ve a correr. ¿No existe primero para reemplazar al marcador de posición? El proceso de compilación se lleva a cabo, por lo que no hay lugar para la supervivencia para la inyección de SQL.
Entonces, ¿cómo logra mybatis precompilación de SQL? De hecho, el marco está utilizando la clase preparada. La clase preparada no solo evita la inyección de SQL, porque ha sido precompilada. Cuando la misma declaración SQL se ejecuta n veces, ahorra el tiempo de compilación (N-1), mejorando así la eficiencia.
Si cambia la declaración anterior a:
<select id = "getNameByUserId" resultType = "String"> Seleccione Nombre del usuario donde id = $ {userId} </select> Cuando ingresamos userId="34;drop table user;" , la declaración impresa se ve así:
Seleccione el nombre del usuario donde id = 34; Drop Tabla User;
En este momento, MyBatis no usa declaraciones precompiladas. Primero realizará la costura de las cuerdas y luego realizará la compilación. Este proceso es el proceso de inyección de SQL en vigencia.
Por lo tanto, al escribir declaraciones de mapeo myBatis, intente usar el formato "#{xxx}". Si tiene que usar parámetros como "$ {xxx}", debe hacer un buen trabajo manualmente filtrado para evitar ataques de inyección SQL.
Resumir
Lo anterior es una explicación detallada del método para prevenir la inyección de SQL por parte de MyBatis presentada a usted. Espero que te sea útil. Si tiene alguna pregunta, déjame un mensaje y el editor le responderá a tiempo. ¡Muchas gracias por su apoyo al sitio web de Wulin.com!