【Seguridad de la red】Explicación detallada de la inyección SQL

1. ¿Qué es la inyección sql?

La inyección de SQL es uno de los métodos de ataque de red más comunes. No utiliza el BUG del sistema operativo para realizar el ataque, sino que apunta a la negligencia de los programadores al escribir, y realiza el inicio de sesión sin cuenta a través de declaraciones SQL, e incluso manipula el base de datos.

 2. La idea general del ataque de inyección SQL 

  1: Encuentra la ubicación de la inyección SQL

  2: Determine el tipo de servidor y el tipo de base de datos de fondo

  3: ataques de inyección SQL contra diferentes características de servidor y base de datos

 3. Ejemplos de ataques de inyección SQL

String sql = "select * from user_table where username=
' "+userName+" ' and password=' "+password+" '";

--当输入了上面的用户名和密码,上面的SQL语句变成:
SELECT * FROM user_table WHERE username=
'’or 1 = 1 -- and password='’

"""
--分析SQL语句:
--条件后面username=”or 1=1 用户名等于 ” 或1=1 那么这个条件一定会成功;

--然后后面加两个-,这意味着注释,它将后面的语句注释,让他们不起作用,这样语句永远都--能正确执行,用户轻易骗过系统,获取合法身份。
--这还是比较温柔的,如果是执行
SELECT * FROM user_table WHERE
username='' ;DROP DATABASE (DB Name) --' and password=''
--其后果可想而知…
"""

4. Cómo defenderse de la inyección SQL

Nota: Cualquier programa con vulnerabilidad de inyección SQL se debe a que el programa necesita aceptar variables ingresadas por el usuario del cliente o parámetros pasados ​​por la URL, y esta variable o parámetro es parte de la instrucción SQL. Para el contenido ingresado por el usuario o los parámetros pasado, siempre debemos estar atentos. Este es el principio de "no se puede confiar en los datos externos" en el campo de la seguridad. Al observar varios métodos de ataque en el campo de la seguridad web, la mayoría de ellos son causados ​​​​por desarrolladores que violan este principio, entonces ¿Qué puede naturalmente, se debe pensar en comenzar con la detección, el filtrado y la verificación de variables para garantizar que las variables sean lo que esperaba el desarrollador.

1. Verifique el tipo y formato de datos variables

Si su instrucción SQL tiene el formato where id={$id}, y todos los id en la base de datos son números, entonces debe asegurarse de que la variable id sea del tipo int antes de que se ejecute el SQL; si acepta buzones , entonces debe verificar y asegurarse estrictamente de que la variable debe estar en el formato del buzón. Otros tipos, como la fecha y la hora, también son iguales. En resumen: siempre que haya una variable con un formato fijo, antes de que se ejecute la instrucción SQL, debe verificarse estrictamente de acuerdo con el formato fijo para asegurarse de que la variable esté en el formato que esperábamos, para que ataques de inyección SQL se puede evitar en gran medida.
Por ejemplo, en nuestro ejemplo anterior de aceptar parámetros de nombre de usuario, el diseño de nuestro producto debe tener una regla de nombre de usuario al comienzo del registro del usuario, como 5-20 caracteres, que solo pueden estar compuestos por letras mayúsculas y minúsculas, números y algunos caracteres seguros. Símbolos, sin caracteres especiales. En este punto, deberíamos tener una función check_username para realizar una verificación unificada. Sin embargo, todavía hay muchas excepciones que no se pueden aplicar a esta regla, como los sistemas de publicación de artículos, los sistemas de comentarios y otros escenarios que deben permitir a los usuarios enviar cadenas arbitrarias, lo que requiere otras soluciones, como el filtrado.

2. Filtrar símbolos especiales

Para las variables cuyo formato fijo no se puede determinar, se debe realizar un filtrado o escape especial de símbolos.

3. Vincule variables, use sentencias precompiladas  

El controlador mysqli de MySQL brinda soporte para declaraciones precompiladas.Diferentes lenguajes de programación tienen métodos para usar declaraciones precompiladas.

De hecho, el uso de declaraciones precompiladas para vincular variables es la mejor manera de evitar la inyección de SQL. La semántica de las declaraciones SQL precompiladas no cambiará. En las declaraciones SQL, las variables se representan con signos de interrogación y los piratas informáticos, sin importar cuán poderosos sean, no se puede cambiar la estructura de la sentencia SQL

5. ¿Qué es la precompilación sql?

1.1: ¿Qué es una declaración preparada? 

Por lo general, nuestro sql recibe la ejecución final y los retornos en la base de datos se pueden dividir en los siguientes tres procesos:

  1. Análisis Léxico y Semántico
  2. Optimice la declaración sql y haga un plan de ejecución
  3. Ejecutar y devolver el resultado.

Llamamos a esta declaración común declaraciones inmediatas.  

Pero en muchos casos, una de nuestras declaraciones SQL puede ejecutarse repetidamente, o solo los valores individuales son diferentes cada vez que se ejecuta (por ejemplo, el valor de la cláusula where de la consulta es diferente, el valor de la cláusula set de la actualización es diferente, y los valores de la inserción son diferentes).
Si necesita pasar por el análisis léxico y semántico anterior, la optimización de declaraciones, la formulación del plan de ejecución, etc. cada vez, la eficiencia obviamente no funcionará.

La llamada declaración precompilada consiste en reemplazar el valor en este tipo de declaración con un marcador de posición, que se puede considerar como una declaración SQL con plantilla o parametrizada. Generalmente, este tipo de declaración se llama declaraciones preparadas o declaraciones parametrizadas. La ventaja de las declaraciones precompiladas es que se pueden resumir
como: compilar una vez y ejecutar varias veces, eliminando la necesidad de análisis y optimización; además, las declaraciones precompiladas pueden evitar la inyección de SQL.
Por supuesto, en términos de optimización, en muchos casos, el plan de ejecución óptimo no se puede determinar simplemente conociendo la plantilla de la declaración SQL, sino que a menudo se necesita estimar el costo a través de valores específicos.

1.2: función de precompilación de MySQL

Tenga en cuenta que la versión anterior de MySQL (anterior a la 4.1) no admite la precompilación del lado del servidor, pero según la situación general actual en el entorno de producción de la industria, básicamente se puede considerar que MySQL admite la precompilación del lado del servidor.

Echemos un vistazo al uso de declaraciones preparadas en MySQL.
(1) Construcción de una tabla Primero, tenemos una tabla de prueba t, cuya estructura es la siguiente:

mysql> show create table t\G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE `t` (
  `a` int(11) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  UNIQUE KEY `ab` (`a`,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

(2) compilar

Precompilaremos  PREPARE stmt_name FROM preparable_stmuna sentencia sql con la sintaxis que pasaremos a continuación

mysql> prepare ins from 'insert into t select ?,?';
Query OK, 0 rows affected (0.00 sec)
Statement prepared

(3) Ejecución

La sintaxis que pasamos EXECUTE stmt_name [USING @var_name [, @var_name] ...]para ejecutar sentencias preparadas

mysql> set @a=999,@b='hello';
Query OK, 0 rows affected (0.00 sec)
 
mysql> execute ins using @a,@b;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0
 
mysql> select * from t;
+------+-------+
| a    | b     |
+------+-------+
|  999 | hello |
+------+-------+
1 row in set (0.00 sec)

Como puede ver, los datos se han insertado correctamente en la tabla.

El alcance de las declaraciones precompiladas en MySQL es a nivel de sesión, pero podemos usar la variable max_prepared_stmt_count para controlar las declaraciones precompiladas máximas globales almacenadas.

mysql> set @@global.max_prepared_stmt_count=1;
Query OK, 0 rows affected (0.00 sec)
 
mysql> prepare sel from 'select * from t';
ERROR 1461 (42000): Can't create more than max_prepared_stmt_count statements (current value: 1)

Cuando la cantidad de entradas precompiladas haya alcanzado el umbral, puede ver que MySQL informará el error que se muestra arriba.

(4) Liberar
Si queremos liberar una declaración precompilada, podemos usar {DEALLOCATE | DROP} PREPARE stmt_namela sintaxis para hacerlo:

mysql> deallocate prepare ins;
Query OK, 0 rows affected (0.00 sec)

6. Por qué PrepareStatement puede prevenir la inyección SQL

El principio es usar el método de precompilación, primero compilar el conjunto de parámetros en la declaración SQL que puede ser controlada por el cliente, generar el conjunto de variables temporales correspondiente y luego usar el método de configuración correspondiente para asignar valores a los elementos. en el conjunto de variables temporales. La función setString() realizará una verificación de tipo obligatoria y una verificación de seguridad en los parámetros entrantes, por lo que se puede evitar la inyección de SQL. El siguiente análisis específico

(1): ¿Por qué la declaración será inyectada por sql?

Porque la declaración es inyectada por SQL porque la estructura de la declaración SQL ha cambiado. Por ejemplo:

"select*from tablename where username='"+uesrname+  
"'and password='"+password+"'"

La estructura de la instrucción sql cambia después de que el usuario ingresa 'o verdadero o'.

select*from tablename where username=''or true or'' and password=''

De esta forma, solo se cuenta cuando el nombre de usuario y la contraseña coinciden, pero después del cambio, se convierte en una relación lógica OR, independientemente de que el nombre de usuario y la contraseña coincidan o no, el valor de retorno de esta fórmula siempre es verdadero;

(2) Por qué la preparación puede evitar la inyección de SQL.

Porque el estilo de preparación es

select*from tablename where username=? and password=?

La instrucción SQL se compilará previamente con la base de datos antes de recibir la entrada del usuario. De esta manera, sin importar el nombre de usuario y la contraseña que ingrese el usuario, el juicio es siempre una relación lógica, lo que evita la inyección de SQL.

En un breve resumen, la razón por la que la parametrización puede evitar la inyección es que una declaración es una declaración, un parámetro es un parámetro y el valor de un parámetro no es parte de la declaración. La base de datos solo se ejecuta de acuerdo con la semántica de la declaración. En cuanto a si correr con una mochila normal o un monstruo, no afectará la ruta de viaje, no es más que la diferencia entre correr más rápido y más lento.

7. ¿Cómo evita mybatis la inyección SQL?  

1. Primero mire la diferencia entre las siguientes dos sentencias SQL:

<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, username, password, role
from user
where username = #{username,jdbcType=VARCHAR}
and password = #{password,jdbcType=VARCHAR}
</select>
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, username, password, role
from user
where username = ${username,jdbcType=VARCHAR}
and password = ${password,jdbcType=VARCHAR}
</select>

La diferencia entre # y $ en mybatis:

1. # Trate los datos entrantes como una cadena y agregue comillas dobles a los datos entrantes automáticamente.
Por ejemplo: donde nombre de usuario = # {nombre de usuario}, si el valor pasado es 111, entonces el valor cuando se analiza en sql es donde nombre de usuario = "111", si el valor pasado es id, entonces el sql analizado es donde nombre de usuario = "identificación". 

2. $ muestra y genera directamente los datos entrantes en sql.
Por ejemplo: donde nombre de usuario = $ {nombre de usuario}, si el valor pasado es 111, entonces el valor cuando se analiza en sql es donde nombre de usuario = 111; si el valor
pasado es ;drop table user;, el sql analizado es: select id, nombre de usuario, contraseña, función del usuario donde nombre de usuario =; usuario de la tabla desplegable;

3. El método # puede evitar la inyección de SQL en gran medida, pero el método $ no puede evitar la inyección de Sql.
4. El método $ generalmente se usa para importar objetos de la base de datos, como el nombre de la tabla.
5. No use $ si generalmente puede usar #. Si tiene que usar parámetros como "${xxx}", debe hacerlo manualmente Filtrarlos Work, para evitar ataques de inyección de sql.
6. En MyBatis, los parámetros en formato "${xxx}" participarán directamente en la compilación de SQL, por lo que no se pueden evitar los ataques de inyección. Pero cuando se trata de nombres de columnas y tablas dinámicas, solo se puede usar el formato de parámetro "${xxx}". Por lo tanto, dichos parámetros deben procesarse manualmente en el código para evitar la inyección.

[Conclusión] Al escribir la declaración de mapeo de MyBatis, intenta usar el formato "#{xxx}". Si tiene que usar parámetros como "${xxx}", debe filtrarlos manualmente para evitar ataques de inyección SQL.

¿Cómo previene mybatis la inyección de sql?

Como un marco de capa de persistencia semiautomático, el marco de MyBatis requiere que escribamos manualmente sus declaraciones SQL, por supuesto, es necesario evitar la inyección de SQL en este momento. De hecho, MyBatis SQL es una función con " entrada + salida ", similar a la estructura de la función, consulte los dos ejemplos anteriores. Entre ellos, el tipo de parámetro indica el tipo de parámetro de entrada y el tipo de resultado indica el tipo de parámetro de salida. Respondiendo a lo anterior, si queremos evitar la inyección de SQL, por supuesto que es necesario trabajar mucho en los parámetros de entrada. La parte que usa # en el código anterior es la parte donde los parámetros de entrada se concatenan en SQL. Después de pasar los parámetros, imprima la instrucción SQL ejecutada y verá que el SQL se ve así:

select id, username, password, role from user where username=? and password=?

No importa qué parámetros se ingresen, el SQL impreso es así. Esto se debe a que MyBatis ha habilitado la función de precompilación. Antes de que se ejecute el SQL, el SQL anterior se enviará a la base de datos para su compilación; al ejecutar, use directamente el SQL compilado y reemplace el marcador de posición "?". Debido a que la inyección de SQL solo puede funcionar en el proceso de compilación, este método evita bien el problema de la inyección de SQL.

[Principio de implementación subyacente] ¿Cómo logra MyBatis la precompilación de SQL? De hecho, en la parte inferior del marco, está trabajando la clase PreparedStatement en JDBC.PreparedStatement es una subclase de Statement con la que estamos muy familiarizados.Sus objetos contienen sentencias SQL compiladas. Este enfoque "listo" no solo puede mejorar la seguridad, sino también mejorar la eficiencia cuando el mismo SQL se ejecuta varias veces. El motivo es que el SQL se ha compilado y no es necesario volver a compilarlo al ejecutarlo de nuevo.

Supongo que te gusta

Origin blog.csdn.net/2301_77160226/article/details/130414616
Recomendado
Clasificación