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.
¿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
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
¿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