Un buscador que enseña de más
La tienda del club vende camisetas. Hay un buscador: escribes un nombre y salen las camisetas.
Una persona escribe una frase rara y de pronto ve todos los productos, incluidos los que estaban ocultos.
No ha adivinado ninguna clave. Ha engañado a la consulta. Hoy aprendes a evitarlo.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Inyección de SQL | Un ataque: el visitante escribe SQL en un campo y el servidor lo ejecuta. | x' OR '1'='1 |
| Consulta preparada | Una consulta que se envía primero con huecos y después con los datos. | $pdo->prepare($sql) |
| Marcador | Un hueco en la consulta donde irá un dato. Se escribe con un signo ?. | WHERE name = ? |
| Parámetro | El dato que ocupa un marcador. Viaja aparte de la consulta. | $stmt->execute([$name]) |
| Lista permitida | Los únicos valores que aceptas. Vale para columnas y orden. | "price" o "name" |
| Escapar | Cambiar los signos especiales de un texto antes de escribirlo en la página. | htmlspecialchars($name) |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Qué es una inyección de SQL
Una consulta es un texto. Si pegas dentro de ese texto lo que escribió el visitante, él puede cambiar la consulta.
Con unas comillas y la palabra OR consigue que la condición sea siempre verdadera.
Mira cómo queda la consulta con un dato de ese tipo.
Pruébalo: la consulta mal hecha
<?php
// MAL: se pega lo que escribe el visitante dentro de la consulta.
$name = "x' OR '1'='1";
$sql = "SELECT * FROM shirt WHERE name = '" . $name . "'";
echo $sql . "\n";
// Cambia $name por "Bufanda" y mira la consulta.
Pruébalo: lo que haría la base de datos
-- Esta es la consulta de antes, ya montada.
SELECT * FROM shirt WHERE name = 'x' OR '1'='1';
-- Ahora busca solo la bufanda.
-- SELECT * FROM shirt WHERE name = 'Bufanda';
Ejemplo resuelto: tres búsquedas
| Lo que escribe | Pegado en la consulta | Con un marcador |
|---|---|---|
| Bufanda | Sale 1 camiseta: la bufanda | Sale 1: busca ese nombre |
| x' OR '1'='1 | Salen las 4: la condición siempre es verdadera | Salen 0: ningún nombre es esa frase |
| Camiseta local | Salen 2: las dos locales | Salen 2: busca ese nombre |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
La defensa: consultas preparadas
En una consulta preparada primero envías la consulta con huecos. Los huecos se escriben con ?.
Después envías los datos por separado. La base de datos ya sabe qué es SQL y qué es un dato, así que nunca los mezcla.
Da igual lo que escriba el visitante: siempre es un dato.
Una consulta preparada con PDO
<?php
// Los signos ? son marcadores: aquí irán los datos, pero por otro camino.
$sql = "SELECT id, name, price FROM shirt WHERE category = ? AND price <= ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$category, $maxPrice]);
$rows = $stmt->fetchAll();
// También puedes ponerles nombre.
$sql = "SELECT id, name FROM shirt WHERE category = :category";
$stmt = $pdo->prepare($sql);
$stmt->execute(["category" => $category]);
Pruébalo: la consulta segura
<?php
// Devuelve la consulta con un marcador y los datos aparte.
function safeQuery(string $name): array {
return ["sql" => "SELECT * FROM shirt WHERE name = ?", "params" => [$name]];
}
$query = safeQuery("x' OR '1'='1");
echo $query["sql"] . "\n";
echo "Parámetro: " . $query["params"][0] . "\n";
// La consulta no cambia, sea lo que sea lo que escriba el visitante.
Repaso rápido: la defensa
Inténtalo
Repaso rápido: la defensa
3 preguntasTus respuestas se corrigen aquí y no se guardan. Una cuenta guarda tus resultados.