c# - type - ¿Cómo ayudan las consultas parametrizadas a la inyección de SQL?
table type sql server (6)
En ambas consultas 1 y 2, el texto del cuadro de texto se inserta en la base de datos. ¿Cuál es el significado de la consulta parametrizada aquí?
1.> -------------
SqlCommand cmd = new SqlCommand("INSERT INTO dbo.Cars " +"VALUES(@TagNbr);" , conn);
cmd.Parameters.Add("@TagNbr", SqlDbType.Int);
cmd.Parameters["@TagNbr"].Value = txtTagNumber.Text;
2.> --------------
int tagnumber = txtTagNumber.Text.ToInt16(); /* EDITED */
INSERT into Cars values(tagnumber.Text); /* then is it the same? */
Además, aquí usaría la validación de expresión regular para detener la inserción de caracteres ilegales.
Imagine una consulta SQL dinámica
sqlQuery=''SELECT * FROM custTable WHERE User='' + Username + '' AND Pass='' + password
así que una simple inyección sql sería simplemente poner el nombre de usuario como
'' OR 1=1--
Esto haría efectivamente la consulta sql:
sqlQuery=''SELECT * FROM custTable WHERE User='''' OR 1=1-- '' AND PASS='' + password
Esto indica que seleccione todos los clientes cuyo nombre de usuario esté en blanco ('''') o 1 = 1, que es un booleano, lo que equivale a verdadero. Luego usa - para comentar el resto de la consulta. Así que esto solo imprimirá toda la tabla de clientes, o hará lo que quiera con ella, si inicia sesión, iniciará sesión con los privilegios del primer usuario, que a menudo puede ser el administrador.
Ahora las consultas parametrizadas lo hacen de manera diferente, con un código como:
sqlQuery=''SELECT * FROM custTable WHERE User=? AND Pass=?''
parameters.add ("Usuario", nombre de usuario) parameters.add ("Pase", contraseña)
donde el nombre de usuario y la contraseña son variables que apuntan al nombre de usuario y contraseña ingresados asociados
Ahora en este punto, puedes estar pensando, esto no cambia nada en absoluto. Seguramente podrías simplemente poner en el campo de nombre de usuario algo así como Nadie O 1 = 1 ''-, haciendo la consulta de manera efectiva:
sqlQuery=''SELECT * FROM custTable WHERE User=Nobody OR 1=1''-- AND Pass=?''
Y esto parecería un argumento válido. Pero, estarías equivocado.
La forma en que funcionan las consultas parametrizadas es que sqlQuery se envía como una consulta, y la base de datos sabe exactamente lo que hará esta consulta, y solo entonces insertará el nombre de usuario y las contraseñas simplemente como valores. Esto significa que no pueden afectar la consulta, porque la base de datos ya sabe lo que hará la consulta. Entonces, en este caso, buscaría un nombre de usuario de
"Nobody OR 1=1''--"
y una contraseña en blanco, que debería aparecer como falsa.
Es bastante comprensible por qué uno se sentiría así.
sqlQuery = "select * from users where username=''+username+'';"
vs
sqlQuery = "select * from users where username=@username;"
Ambas consultas anteriores parecen hacer lo mismo. Pero en realidad no lo hacen.
El primero usa la entrada para una consulta, este último decide sobre la consulta, pero solo sustituye las entradas tal como están durante la ejecución de la consulta.
Para ser más claros, los valores de los parámetros se ubican en algún lugar de la pila donde se almacena la memoria de las variables y se utilizan para buscar cuando sea necesario.
Entonces, si tuviéramos que dar '' OR ''1''=''1
como entrada en el nombre de usuario, el primero construiría dinámicamente nuevas consultas o consultas como parte de la cadena de consulta sql sqlQuery
que luego se ejecutará.
Mientras esté en la misma entrada, este último buscará '' OR ''1''=''
en el campo de username
de username
de la tabla de users
con la consulta estáticamente especificada en la cadena de consulta sqlQuery
Solo para consolidarlo, así es como usa parámetros para realizar consultas:
SqlCommand command = new SqlCommand(sqlQuery,yourSqlConnection);
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@username";
parameter.Value = "xyz";
command.Parameters.Add(parameter);
La inyección sql ocurre cuando un parámetro posible tiene sql dentro de él y las cadenas no se manejan como debería ser
p.ej:
var sqlquerywithoutcommand = "select * from mytable where rowname = ''" + condition+''''";
y la condición es una cadena que proviene del usuario en la solicitud. Si la condición es maliciosa, por ejemplo, diga:
var sqlquerywithoutcommand = "select * from mytable where rowname = ''" + "a'' ;drop table mytable where ''1=1"+"''";
podrías terminar ejecutando scripts maliciosos.
pero al usar parámetros, la entrada se limpiará de cualquier carácter que pueda escapar de los caracteres de cadena ...
puede estar seguro de que, sin importar lo que ingrese, no podrá ejecutar scripts de inyección.
utilizando el objeto de comando con parámetros el sql realmente ejecutado se vería así
select * from mytable where rowname = ''a'''';drop table mytable where 1=1''''''
en esencia, buscará una fila con rowname = a ''; drop table mytable donde 1 = 1'' y no ejecutará el script restante
Las consultas parametrizadas manejan todo: ¿por qué resolver el problema?
Con las consultas parametrizadas, además de la inyección general, obtiene todos los tipos de datos manejados, números (int y float), cadenas (con comillas incorporadas), fechas y horas (no hay problemas de formato o localización cuando .ToString () no se llama con la cultura invariante y su cliente se mueve a una máquina con un formato de fecha inesperado).
Las consultas parametrizadas permiten que el cliente pase los datos por separado desde el texto de la consulta. Donde más libre de texto haría la validación + escapando. Por supuesto, la parametrización no ayuda contra otro tipo de inyección, pero como los parámetros se pasan por separado, no se utilizan como consulta de texto de ejecución.
Una buena analogía sería el bit de ejecución "reciente" utilizado con la mayoría de los procesadores modernos y el sistema operativo para proteger del desbordamiento del búfer. Todavía permite el desbordamiento del búfer pero evita la ejecución de los datos inyectados.
Las consultas parametrizadas realizan la sustitución adecuada de los argumentos antes de ejecutar la consulta SQL. Elimina por completo la posibilidad de que la entrada "sucia" cambie el significado de su consulta. Es decir, si la entrada contiene SQL, no puede formar parte de lo que se ejecuta porque el SQL nunca se inyecta en la instrucción resultante.