Laboratorio de inyección SQL: ataca una búsqueda débil, corrige la consulta y demuéstralo

Este laboratorio da a cada alumno una pequeña tienda cuya búsqueda de productos es vulnerable a la inyección SQL. El alumno la ataca desde el terminal del laboratorio con curl, haciendo que muestre productos que no están a la venta y los usuarios y contraseñas de la tienda, y después corrige el código dentro del contenedor en marcha para que la consulta esté parametrizada, reinicia la tienda y ve cómo los mismos ataques no encuentran nada mientras las búsquedas normales siguen funcionando.

Lo hemos diseñado nosotros a partir de la sola imagen pública de Python, así que no hay ninguna aplicación de terceros que atacar: solo un programa breve nuestro que está mal a propósito. La única regla es la habitual de un laboratorio de ataque: ataca solo tu propia copia. La copia no tiene ruta a internet ni a ningún otro alumno, y un alumno no debe dirigir nunca una herramienta contra un sitio que no es suyo.

Qué aprenden los alumnos

Cómo se produce una inyección SQL: un programa pega lo que escribió un visitante en el texto de su pregunta a la base de datos, de modo que una comilla termina la pregunta antes de tiempo y el resto lo escribe el visitante. Salen de la pregunta con un OR siempre verdadero, leen otra tabla con un UNION, encuentran la línea responsable y la sustituyen por una consulta parametrizada, que envía la pregunta y el valor por separado, de modo que un valor nunca puede formar parte de la pregunta. También comprueban que la corrección no ha roto el uso normal, lo que incluye un producto cuyo nombre contiene una comilla. Es adecuado para las unidades de programación segura y de seguridad de aplicaciones web, y para su parte legal: la autorización y el alcance. Consulta la redacción exacta en la unidad de tu organismo certificador.

Ejecútalo en tu navegador

La tienda es el servicio llamado app, y el terminal del laboratorio llega a ella por ese nombre. Un comando docker en el terminal puede ver, abrir, reiniciar y leer los registros del servicio del laboratorio: no puede crear, descargar ni eliminar nada. El programa está en un volumen con nombre, así que lo que el alumno guarda sigue ahí después de detener e iniciar de nuevo el laboratorio.

  1. Abre la página Contenedor. Abre «Crear» en la barra y elige «Ejecutar un contenedor». Cualquiera puede abrir la página, y el laboratorio de Git y el de SQL se inician sin cuenta. Todos los demás laboratorios necesitan una cuenta gratuita: crea una, inicia sesión y pulsa «Iniciar».
  2. Busca el laboratorio. La tarjeta «Laboratorios de ejemplo» lista todos los ejemplos. Busca Inyección SQL: encuéntrala y corrígela.
  3. Pulsa «Iniciar». «Iniciar» lo ejecuta tal cual, con una sola pulsación. «Editar el archivo primero» abre el archivo compose para que lo cambies antes de iniciarlo.
  4. Ábrelo. En la página del laboratorio, abre el terminal junto al laboratorio. Ejecuta curl -s -G --data-urlencode "q=pen" http://app:8000/search para buscar en la tienda y después haz que muestre demasiado con una búsqueda de x' OR 1=1 -- . docker exec -it app vi /tmp/app/app.py abre el programa para editarlo, docker restart app ejecuta la nueva versión, y docker exec app sh /tmp/app/lab-check muestra PASS o FAIL para cuatro cosas. El enlace del laboratorio, Corner Shop search page, abre el formulario de búsqueda en una pestaña.

Qué pedir a los alumnos que entreguen

La salida del ataque antes de la corrección y después, y la de docker exec app sh /tmp/app/lab-check al final, para que el cambio se vea en el propio terminal del alumno. Después, la línea que han cambiado y una frase con sus propias palabras sobre por qué la nueva línea no se puede inyectar, qué podría haber hecho un atacante con la antigua y qué más ayudaría (la cuenta con la que se conecta la aplicación, contraseñas que nunca se guardan en texto plano). La comprobación dice si la tienda se comporta como debe; solo la explicación dice si se ha entendido.

La comprobación es la del propio laboratorio: lab-check pregunta a la tienda en marcha en su propia dirección, así que informa de lo que hace la tienda y no de lo que dice un archivo, y termina con éxito solo si pasan las cuatro líneas. Nada se califica automáticamente. Estos laboratorios se usan a menudo con alumnos de 16 y 17 años: una copia es privada del alumno, un miembro del personal que imparte el módulo puede abrirla, y abrir el trabajo de un alumno queda anotado en el registro de accesos, que el alumno puede leer.

Una lección básica en este laboratorio

SQL Injection Fix Basics es una lección breve hecha en este laboratorio, con cada paso explicado y un botón Ejecutar que escribe su comando en el terminal del alumno. Empieza por la regla única, busca en la tienda, hace que muestre todos los productos, corrige la línea con un comando, reinicia la tienda y la ataca de nuevo, y después ejecuta la comprobación. Leer el código y escribir la corrección a mano quedan para el alumno.

Una cuenta personal gratuita la recibe en el módulo Basics, que está en Inicio, cada centro puede copiarla de la carpeta Basics de la Biblioteca, y un centro nuevo la tiene en un módulo llamado Lab Basics (Sample). Es deliberadamente breve: muestra a un docente lo que es una lección hecha en un laboratorio, y el laboratorio hace el resto. Cópiala en un módulo propio para cambiarla.

El código en GitHub

El archivo compose ejecuta la imagen oficial de Python, fijada a una versión, como único servicio, y escribe el programa de la tienda al arrancar. Python tiene licencia de la Python Software Foundation y nosotros no lo distribuimos. La prueba del repositorio recorre el laboratorio como un alumno: el ataque, la corrección, una parada y un inicio, y volver a empezar, con los mismos límites que aplica la plataforma.

Asígnalo como trabajo

Indica en la tarea qué atacar, qué línea corregir y qué entregar.

  1. Crea el laboratorio. En tu módulo añade una tarea y elige la tarjeta «Laboratorio de contenedores», y después «En un repositorio de GitHub». Indica https://github.com/mitsurutech/lab-sqli-fix con la rama main. El archivo compose es el predeterminado, compose.yaml. Haz un fork del repositorio antes si quieres modificarlo.
  2. Publica y pruébalo. «Publicar» fija el commit que te mostraron, así que un cambio posterior en el repositorio no altera un laboratorio que ya has asignado. Inicia primero tu propia copia.
  3. Asígnalo. Asígnalo como cualquier tarea, con una fecha de entrega si quieres, e indica en la tarea qué hacer y qué entregar.
  4. Califica lo entregado. Abre la copia de un alumno y el trabajo que ha entregado, califícalo y devuélvelo con un motivo si necesita más.

Preguntas frecuentes

¿Qué pasa si un alumno guarda un error en el programa?
El laboratorio arranca igualmente. Un programa que no compila al arrancar se conserva al lado como app.py.broken y se vuelve a escribir el débil. Para empezar a propósito desde el programa débil, ejecuta docker exec app rm /tmp/app/app.py y después docker restart app.
¿Hay una parte sobre cuentas y privilegios de la base de datos?
No. La tienda usa SQLite, que no tiene cuentas a las que conceder permisos, y un laboratorio no tiene internet para instalar un cliente de un servidor de bases de datos. El mínimo privilegio es un buen tema que pedir en la explicación escrita.
¿Tiene el alumno que instalar algo o llegar a internet?
No. Python y curl están en las imágenes del propio laboratorio, el terminal está en el navegador, y la copia del laboratorio no tiene salida a internet.