Kodokon kodokon.com

Seguridad: inyección SQL, privilegios, sentencias preparadas

Reproduce una inyección SQL, neutralízala con sentencias preparadas y aplica el mínimo privilegio.

11 min · 3 preguntas

Abrir esta lección en Kodokon

Una inyección SQL ocurre en el momento en que datos no confiables se concatenan en el texto de una consulta. El atacante proporciona un valor que cierra la cadena y secuestra la lógica. Reproduzcamos el ataque sobre una tabla users: concatenar directamente la entrada ada' OR '1'='1 convierte un filtro preciso en una condición siempre verdadera.

SQL
CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  is_admin INTEGER NOT NULL DEFAULT 0
);

INSERT INTO users (id, name, is_admin)
VALUES (1, 'ada', 0), (2, 'root', 1);

-- Dangerous concatenation (NEVER do this)
-- input = ada' OR '1'='1
SELECT * FROM users
WHERE name = 'ada' OR '1'='1';
La consulta inyectada devuelve TODAS las filas.

El payload funciona porque la comilla cierra prematuramente el literal 'ada', y luego OR '1'='1' añade una condición universalmente verdadera. Una variante añade -- para comentar el resto de la consulta original. La lección: mientras los datos y el código compartan la misma cadena, ningún escape manual es realmente fiable.

SQL
-- Positional placeholder
SELECT * FROM users WHERE name = ?;

-- Named placeholder
SELECT * FROM users WHERE name = :name;
Dos formas de parámetros vinculados en SQLite.

El remedio es la sentencia preparada: el driver primero compila la estructura de la consulta, luego vincula los valores por separado. Los datos vinculados nunca se analizan como SQL, solo se comparan. Como ventaja adicional, la estructura compilada es reutilizable: vincular varios valores de forma sucesiva evita recompilar el plan en cada llamada.

SQL
-- The bound value stays data, not SQL
SELECT * FROM users
WHERE name = :name;
-- :name = ada' OR '1'='1
-- -> 0 rows: no user
--    is literally named that
El mismo payload, ahora inofensivo.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. ¿Por qué una sentencia preparada con parámetros impide la inyección SQL?
    • Porque cifra los valores transmitidos
    • Porque el valor vinculado se trata como dato, nunca se analiza como SQL
    • Porque escapa automáticamente las comillas en la cadena
    • Porque limita la longitud de la entrada del usuario
  2. El payload ' OR '1'='1 logra la inyección porque...
    • satura la memoria del servidor de base de datos
    • cierra el literal de cadena y luego añade una condición siempre verdadera
    • elimina la tabla a la que apunta la consulta
    • cambia los privilegios del usuario actual
  3. ¿Puedes vincular el nombre de una tabla mediante un parámetro ??
    • Sí, los marcadores de posición aceptan cualquier tipo de identificador
    • No: los marcadores de posición solo vinculan valores; un identificador debe validarse contra una lista blanca
    • Sí, pero solo con la forma con nombre :name
    • Sí, siempre que la tabla ya exista