La idea es muy simple: la consulta y los datos se envían al servidor de la base de datos por separado .
Eso es todo.
La raíz del problema de inyección SQL está en la mezcla del código y los datos.
De hecho, nuestra consulta SQL es un programa legítimo . Y estamos creando dicho programa dinámicamente, agregando algunos datos sobre la marcha. Por lo tanto, los datos pueden interferir con el código del programa e incluso alterarlo, como lo muestra cada ejemplo de inyección SQL (todos los ejemplos en PHP / Mysql):
$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";
producirá una consulta regular
SELECT * FROM users where id=1
mientras este código
$spoiled_data = "1; DROP TABLE users;"
$query = "SELECT * FROM users where id=$spoiled_data";
producirá una secuencia maliciosa
SELECT * FROM users where id=1; DROP TABLE users;
Funciona porque estamos agregando los datos directamente al cuerpo del programa y se convierte en una parte del programa, por lo que los datos pueden alterar el programa y, dependiendo de los datos pasados, tendremos una salida regular o una tabla users
eliminada.
Si bien en el caso de declaraciones preparadas no modificamos nuestro programa, permanece intacto.
Ese es el punto.
Estamos enviando un programa al servidor primero
$db->prepare("SELECT * FROM users where id=?");
donde los datos se sustituyen por alguna variable llamada parámetro o marcador de posición.
Tenga en cuenta que exactamente la misma consulta se envía al servidor, ¡sin ningún dato! Y luego enviamos los datos con la segunda solicitud, esencialmente separados de la consulta en sí:
$db->execute($data);
por lo que no puede alterar nuestro programa y hacer daño.
Bastante simple, ¿no es así?
Lo único que tengo que agregar que siempre se omite en todos los manuales:
Las declaraciones preparadas pueden proteger solo literales de datos , pero no se pueden usar con ninguna otra parte de consulta.
Entonces, una vez que tengamos que agregar, por ejemplo, un identificador dinámico , un nombre de campo, por ejemplo, las declaraciones preparadas no pueden ayudarnos. He explicado el asunto recientemente , así que no me repetiré.
$spoiled_data = "1; DROP TABLE users;"
->$query = "SELECT * FROM users where id=$spoiled_data";
, en comparación con:$db->prepare("SELECT * FROM users where id=?");
->$data = "1; DROP TABLE users;"
->$db->execute($data);
. ¿No harán lo mismo?Aquí está SQL para configurar un ejemplo:
La clase Inject es vulnerable a la inyección SQL. La consulta se pega dinámicamente junto con la entrada del usuario. La intención de la consulta era mostrar información sobre Bob. Ya sea salario o bonificación, según la aportación del usuario. Pero el usuario malintencionado manipula la entrada que corrompe la consulta agregando el equivalente de un 'o verdadero' a la cláusula where para que se devuelva todo, incluida la información sobre Aaron que se suponía que estaba oculta.
Al ejecutar esto, el primer caso es con uso normal, y el segundo con la inyección maliciosa:
No debe compilar sus sentencias SQL con concatenación de cadenas de entrada del usuario. No solo es vulnerable a la inyección, sino que también tiene implicaciones de almacenamiento en caché en el servidor (la instrucción cambia, por lo que es menos probable que obtenga un acierto en la caché de la instrucción SQL, mientras que el ejemplo de enlace siempre ejecuta la misma instrucción).
Aquí hay un ejemplo de enlace para evitar este tipo de inyección:
Ejecutar esto con la misma entrada que el ejemplo anterior muestra que el código malicioso no funciona porque no hay PaymentType que coincida con esa cadena:
fuente
PREPARE
crea una declaración con nombre fijo que ya está analizada (es decir, la declaración ya no va a cambiar independientemente de la entrada) mientrasEXECUTE
ejecuta la declaración con nombre que vincula los parámetros. Dado quePREPARE
solo tiene una duración de sesión, realmente parece que está destinado por razones de rendimiento, no para evitar la inyección a través de scripts psql. Para el acceso a psql, podría otorgar permisos a los procedimientos almacenados y vincular los parámetros dentro de los procesos.Básicamente, con las declaraciones preparadas, los datos que provienen de un posible pirata informático se tratan como datos, y no hay forma de que puedan mezclarse con su aplicación SQL y / o interpretarse como SQL (lo que puede suceder cuando los datos pasados se colocan directamente en su aplicación SQL).
Esto se debe a que las declaraciones preparadas "preparan" la consulta SQL primero para encontrar un plan de consulta eficiente y envían los valores reales que presumiblemente provienen de un formulario más tarde, en ese momento la consulta se ejecuta realmente.
Más información excelente aquí:
Declaraciones preparadas e inyección SQL
fuente
Leí las respuestas y aún sentí la necesidad de enfatizar el punto clave que ilumina la esencia de las declaraciones preparadas. Considere dos formas de consultar la base de datos de uno donde la entrada del usuario está involucrada:
Enfoque ingenuo
Uno concatena la entrada del usuario con alguna cadena parcial de SQL para generar una declaración SQL. En este caso, el usuario puede incrustar comandos SQL maliciosos, que luego se enviarán a la base de datos para su ejecución.
Por ejemplo, la entrada de usuarios malintencionados puede llevar a
SQLString
ser igual a"SELECT * FROM CUSTOMERS WHERE NAME='James';DROP TABLE CUSTOMERS;'
Debido al usuario malicioso,
SQLString
contiene 2 declaraciones, donde la segunda ("DROP TABLE CUSTOMERS"
) causará daños.Declaraciones preparadas
En este caso, debido a la separación de la consulta y los datos, la entrada del usuario nunca se trata como una declaración SQL y , por lo tanto, nunca se ejecuta . Es por esta razón, que cualquier código SQL malicioso inyectado no causaría ningún daño. Por lo tanto
"DROP TABLE CUSTOMERS"
, nunca se ejecutará en el caso anterior.En pocas palabras, con las declaraciones preparadas, el código malicioso introducido a través de la entrada del usuario no se ejecutará.
fuente
Cuando crea y envía una declaración preparada al DBMS, se almacena como la consulta SQL para su ejecución.
Posteriormente, vincula sus datos a la consulta de modo que el DBMS use esos datos como parámetros de consulta para la ejecución (parametrización). El DBMS no utiliza los datos que vincula como complemento de la consulta SQL ya compilada; son simplemente los datos.
Esto significa que es fundamentalmente imposible realizar la inyección de SQL utilizando declaraciones preparadas. La naturaleza misma de las declaraciones preparadas y su relación con el DBMS lo impide.
fuente
En SQL Server , el uso de una declaración preparada definitivamente es a prueba de inyección porque los parámetros de entrada no forman la consulta. Significa que la consulta ejecutada no es una consulta dinámica. Ejemplo de una declaración vulnerable de inyección SQL.
Ahora, si el valor en la variable inoutusername es algo así como 'o 1 = 1 -, esta consulta ahora se convierte en:
Y el resto se comenta después
--
, por lo que nunca se ejecuta y se omite al usar el ejemplo de la declaración preparada como se muestra a continuación.Entonces, en efecto, no puede enviar otro parámetro, evitando así la inyección de SQL ...
fuente
La frase clave es
need not be correctly escaped
. Eso significa que no debe preocuparse por las personas que intentan escribir guiones, apóstrofes, citas, etc.Todo se maneja por ti.
fuente
Supongamos que tiene eso en un Servlet que tiene razón. Si una persona malévola pasó un valor malo para 'filtro', podría hackear su base de datos.
fuente
Causa raíz # 1 - El problema del delimitador
La inyección SQL es posible porque usamos comillas para delimitar cadenas y también para ser partes de cadenas, lo que hace imposible interpretarlas a veces. Si tuviéramos delimitadores que no pudieran usarse en datos de cadena, la inyección de sql nunca habría sucedido. Resolver el problema del delimitador elimina el problema de inyección sql. Las consultas de estructura hacen eso.
Causa raíz # 2: la naturaleza humana, las personas son astutas y algunas personas astutas son maliciosas y todas las personas cometen errores
La otra causa raíz de la inyección de sql es la naturaleza humana. Las personas, incluidos los programadores, cometen errores. Cuando comete un error en una consulta estructurada, su sistema no es vulnerable a la inyección SQL. Si no está utilizando consultas estructuradas, los errores pueden generar vulnerabilidad de inyección SQL.
Cómo las consultas estructuradas resuelven las causas raíz de la inyección SQL
Las consultas estructuradas resuelven el problema del delimitador colocando comandos sql en una instrucción y colocando los datos en una instrucción de programación separada. Las declaraciones de programación crean la separación necesaria.
Las consultas estructuradas ayudan a evitar que los errores humanos creen agujeros de seguridad críticos. Con respecto a los humanos que cometen errores, la inyección de sql no puede ocurrir cuando se utilizan consultas de estructura. Hay formas de prevenir la inyección de sql que no implican consultas estructuradas, pero el error humano normal en esos enfoques generalmente conduce a al menos una cierta exposición a la inyección de sql. Las consultas estructuradas son a prueba de fallas de la inyección SQL. Puede cometer todos los errores del mundo, casi, con consultas estructuradas, igual que cualquier otra programación, pero ninguna de las que pueda hacer puede convertirse en un sistema asumido por inyección SQL. Es por eso que a la gente le gusta decir que esta es la forma correcta de prevenir la inyección de sql.
Entonces, ahí lo tiene, las causas de la inyección de SQL y las consultas estructuradas de la naturaleza que las hacen imposibles cuando se usan.
fuente