Una web que se fía del usuario
Probar una aplicación web es intentar fallos conocidos en tu propia copia para encontrar los agujeros antes que nadie. Una tienda, un blog del instituto o una agenda comparten los mismos tres fallos más comunes.
Hoy aprenderás a reconocerlos en una petición, a explicar por qué ocurren y a ver cómo se arreglan.
Al terminar esta lección
Nota
Puedo reconocer en una petición un intento de inyección, de script o de salida de carpeta.
La regla de este laboratorio
Importante
Prueba solo en tu copia del laboratorio y solo con permiso. Hacerlo en la web de otra persona es un delito aunque no rompas nada. El laboratorio es una web insegura a propósito, sin salida a internet.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Petición | un mensaje que el navegador envía a un servidor | |
| Entrada del usuario | cualquier texto que escribe quien usa la web | |
| Inyección SQL | meter órdenes de base de datos en un campo de texto | |
| Script entre sitios | meter código en una página que otros van a ver | XSS |
| Consulta parametrizada | una consulta donde el dato viaja aparte de la orden | |
| Validar | comprobar que un dato tiene la forma esperada |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Todos estos fallos nacen de la misma confusión
Una web recibe datos de quien la usa: un nombre, una búsqueda, el nombre de un archivo. Si el programa mezcla esos datos con sus propias órdenes, el dato puede convertirse en orden.
Esa confusión entre dato y orden está detrás de la inyección SQL, de los scripts en páginas y de las salidas de carpeta.
Los tres fallos en una petición
| Fallo | Qué intenta el atacante | Cómo se ve en la petición |
|---|---|---|
| Inyección SQL | Cambiar la consulta a la base de datos | Texto como: ' OR '1'='1 |
| Script entre sitios | Meter código en una página | Texto como: <script>alert(1)</script> |
| Salida de carpeta | Leer archivos fuera de la carpeta permitida | Texto como: ../../etc/passwd |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Por qué falla una consulta con texto pegado
Imagina una tienda que busca un cliente con la orden "dame las filas donde nombre sea lo que escribió el usuario". Si el programa pega el texto tal cual, un texto con comillas cambia el sentido de la orden.
El siguiente bloque usa una base de datos inventada que vive solo en la memoria de la página. Pulsa Ejecutar y mira cuántas filas salen.
Pegar el texto devuelve filas de más
import sqlite3
bd = sqlite3.connect(":memory:")
bd.execute("CREATE TABLE clientes (nombre TEXT, pedido TEXT)")
bd.execute("INSERT INTO clientes VALUES ('Ana', 'camiseta')")
bd.execute("INSERT INTO clientes VALUES ('Luis', 'gorra')")
escrito = "Ana' OR '1'='1"
orden = "SELECT nombre FROM clientes WHERE nombre = '" + escrito + "'"
print("Orden que se envía:", orden)
print("Filas que salen:", len(bd.execute(orden).fetchall()))
La consulta parametrizada trata el texto como dato
import sqlite3
bd = sqlite3.connect(":memory:")
bd.execute("CREATE TABLE clientes (nombre TEXT, pedido TEXT)")
bd.execute("INSERT INTO clientes VALUES ('Ana', 'camiseta')")
bd.execute("INSERT INTO clientes VALUES ('Luis', 'gorra')")
escrito = "Ana' OR '1'='1"
# El signo ? reserva un hueco: el dato va aparte de la orden.
filas = bd.execute("SELECT nombre FROM clientes WHERE nombre = ?", (escrito,)).fetchall()
print("Filas que salen:", len(filas))
Qué enseñan los dos bloques
El primero escribe que salen 2 filas, aunque ningún cliente se llama así. Las comillas del texto cerraron la condición y OR '1'='1' es siempre verdadero.
El segundo escribe 0 filas. Con el hueco ?, todo el texto es un nombre, y ningún cliente se llama así. Esa es la defensa: la consulta parametrizada.
Un script en una página llega a todos
Si una web enseña tal cual lo que escribió un usuario, por ejemplo en un comentario, ese texto puede llevar código. Cada visitante que abra la página lo ejecutaría en su navegador.
La defensa es escapar la salida: cambiar los signos especiales por una forma inofensiva antes de mostrarlos.
Escapar convierte el código en texto
import html
comentario = "<script>alert(1)</script>"
print("Sin escapar:", comentario)
print("Escapado:", html.escape(comentario))
# Cambia el comentario por "<b>hola</b>" y vuelve a ejecutar.
Un error frecuente
Advertencia
Mucha gente cree que basta con una lista de textos prohibidos. Una lista frena lo conocido y falla ante una forma nueva. La defensa de verdad está en el código: consultas parametrizadas, salida escapada y datos validados.
Nivel bajo y nivel alto de seguridad
En el laboratorio, el nivel de seguridad empieza en bajo. Cada ejercicio funciona con el código inseguro. Si lo subes a alto, el mismo ejercicio usa el código arreglado.
La enseñanza está en comparar los dos: qué hacía mal el código bajo y qué hace el alto en su lugar.
Para ir más lejos: nivel bajo y alto
Después de esta lección, el laboratorio abre DVWA. Entra como admin con la clave password, haz un ejercicio en nivel bajo y repítelo en nivel alto.
Escribe un párrafo: qué hacía mal el código bajo y qué cambia en el alto. Usa las palabras de la lección: dato, orden, parametrizada, escapar y validar.