security prevent ¿Cómo funciona la inyección SQL del cómic XKCD de “Bobby Tables”?




url sql injection (10)

En este caso, 'no es un carácter de comentario. Se utiliza para delimitar cadenas literales. El artista del cómic está apostando a la idea de que la escuela en cuestión tiene un sql dinámico en algún lugar que se parece a esto:

$sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";

Así que ahora el carácter 'termina la cadena literal antes de que el programador lo estuviera esperando. Combinado con el; Para finalizar la instrucción, un atacante ahora puede agregar cualquier sql que desee. El - comentario al final es para asegurarse de que cualquier sql restante en la declaración original no impida que la consulta se compile en el servidor.

FWIW, también creo que el cómic en cuestión tiene un importante detalle erróneo: si estás pensando en sanear las entradas de tu base de datos, como sugiere el cómic, todavía lo estás haciendo mal. En su lugar, debe pensar en términos de poner en cuarentena las entradas de la base de datos, y la forma correcta de hacerlo es mediante consultas parametrizadas.

Solo mirando a

(Fuente: https://xkcd.com/327/ )

¿Qué hace este SQL:

Robert'); DROP TABLE STUDENTS; --

Sé que ambos son para comentarios, pero ¿no se comenta la palabra DROP también, ya que es parte de la misma línea?


Así es como funciona: Supongamos que el administrador está buscando registros de estudiantes

Robert'); DROP TABLE STUDENTS; --

Dado que la cuenta de administrador tiene altos privilegios, es posible eliminar la tabla de esta cuenta.

El código para recuperar el nombre de usuario de la solicitud es

Ahora la consulta sería algo como esto (para buscar en la tabla de estudiantes)

String query="Select * from student where username='"+student_name+"'";

statement.executeQuery(query); //Rest of the code follows

La consulta resultante se convierte en

Select * from student where username='Robert'); DROP TABLE STUDENTS; --

Dado que la entrada del usuario no está saneada, la consulta anterior se manipula en 2 partes

Select * from student where username='Robert'); 

DROP TABLE STUDENTS; --

El doble guión (-) solo comentará la parte restante de la consulta.

Esto es peligroso ya que puede anular la autenticación de contraseña, si está presente

El primero hará la búsqueda normal.

El segundo abandonará la tabla si la cuenta tiene suficientes privilegios (generalmente, la cuenta del administrador de la escuela ejecutará dicha consulta y tendrá los privilegios mencionados anteriormente).


Digamos que el nombre fue usado en una variable, $Name . A continuación, ejecute esta consulta:

INSERT INTO Students VALUES ( '$Name' )

El código está colocando por error cualquier cosa que el usuario proporcionó como variable. Querías que el SQL fuera:

INSERT INTO VALORES DE LOS ESTUDIANTES (' Robert Tables `)

Pero un usuario inteligente puede suministrar lo que quiera:

Insertar valores en los estudiantes (' robert'); DROP TABLE Estudiantes; - ')

Lo que obtienes es:

INSERT INTO Students VALUES ( 'Robert' );  DROP TABLE STUDENTS; --' )

El -- solo comenta el resto de la línea.


Deja caer la mesa de los alumnos.

El código original en el programa de la escuela probablemente se parece a algo como

q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";

Esta es la forma ingenua de agregar entrada de texto a una consulta, y es muy mala , como verá.

Después de los valores del primer nombre, segundo nombre del cuadro de texto FNMName.Text (que es Robert'); DROP TABLE STUDENTS; -- Robert'); DROP TABLE STUDENTS; -- Robert'); DROP TABLE STUDENTS; -- ) y el último cuadro de texto LName.Text (llamémoslo Derper ) se concatenan con el resto de la consulta, el resultado ahora son en realidad dos consultas separadas por el terminador de la instrucción (punto y coma). La segunda consulta ha sido inyectada en la primera. Cuando el código ejecuta esta consulta en la base de datos, se verá así

INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')

que, en un lenguaje sencillo, se traduce aproximadamente a las dos consultas:

Agregue un nuevo registro a la tabla de Estudiantes con un valor de Nombre de 'Robert'

y

Eliminar la tabla de alumnos

Todo después de la segunda consulta se marca como un comentario : --', 'Derper')

El ' en el nombre del estudiante no es un comentario, es el delimitador de la cadena de cierre. Dado que el nombre del estudiante es una cadena, se necesita sintácticamente para completar la consulta hipotética. Los ataques de inyección solo funcionan cuando la consulta SQL inyecta resultados en SQL válido .

Editado nuevamente según el astuto comentario de dan04 .


Como todos los demás ya han señalado, el '); cierra la declaración original y luego sigue una segunda declaración. La mayoría de los marcos, incluidos lenguajes como PHP, tienen configuraciones de seguridad predeterminadas ahora que no permiten múltiples declaraciones en una cadena de SQL. En PHP, por ejemplo, solo puede ejecutar varias declaraciones en una cadena SQL utilizando la función mysqli_multi_query .

Sin embargo, puede manipular una declaración SQL existente a través de la inyección de SQL sin tener que agregar una segunda declaración. Digamos que tiene un sistema de inicio de sesión que verifica un nombre de usuario y una contraseña con esta sencilla selección:

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);

Si proporciona peter como nombre de usuario y el secret como contraseña, la cadena SQL resultante se vería así:

SELECT * FROM users WHERE username='peter' and (password='secret')

Todo está bien. Ahora imagine que proporciona esta cadena como la contraseña:

' OR '1'='1

Entonces la cadena SQL resultante sería esta:

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')

Eso le permitiría iniciar sesión en cualquier cuenta sin saber la contraseña. Por lo tanto, no necesita poder usar dos declaraciones para usar la inyección de SQL, aunque puede hacer cosas más destructivas si puede proporcionar varias declaraciones.


Digamos que ingenuamente escribiste un método de creación de estudiantes como este:

void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}

Y alguien entra el nombre de Robert'); DROP TABLE STUDENTS; -- Robert'); DROP TABLE STUDENTS; --

Lo que se ejecuta en la base de datos es esta consulta:

INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')

El punto y coma finaliza el comando de inserción y comienza otro; El - comenta el resto de la línea. Se ejecuta el comando DROP TABLE ...

Es por esto que los parámetros de enlace son una buena cosa.


El ' carácter en SQL se utiliza para constantes de cadena. En este caso, se utiliza para finalizar la constante de cadena y no para comentarios.


Una comilla simple es el comienzo y el final de una cadena. Un punto y coma es el final de una declaración. Así que si estuvieran haciendo una selección como esta:

Select *
From Students
Where (Name = '<NameGetsInsertedHere>')

El SQL se convertiría en:

Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
--             ^-------------------------------^

En algunos sistemas, la select se ejecutaría primero, seguida de la declaración de drop . El mensaje es: NO INCLUYA VALORES EN SU SQL. En su lugar usa parámetros!


El escritor de la base de datos probablemente hizo una

sql = "SELECT * FROM STUDENTS WHERE (STUDENT_NAME = '" + student_name + "') AND other stuff";
execute(sql);

Si student_name es el que se da, eso hace la selección con el nombre "Robert" y luego elimina la tabla. La parte "-" cambia el resto de la consulta dada en un comentario.


No, ' no es un comentario en SQL, sino un delimitador.

Mamá supuso que el programador de la base de datos hizo una solicitud con el siguiente aspecto:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');

(por ejemplo) para agregar el nuevo alumno, donde el contenido de la variable $xxx se sacó directamente de un formulario HTML, sin verificar el formato ni escapar de los caracteres especiales.

Así que si $firstName contiene a Robert'); DROP TABLE students; -- Robert'); DROP TABLE students; -- Robert'); DROP TABLE students; -- El programa de la base de datos ejecutará la siguiente solicitud directamente en la base de datos:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');

es decir. terminará pronto la instrucción de inserción, ejecutará cualquier código malicioso que el cracker desee, luego comente el resto del código que pueda haber.

Mmm, soy demasiado lento, ya veo 8 respuestas antes que la mía en la banda naranja ... :-) Un tema popular, parece.





sql-injection