Séptima Parte -> Inyección SQL Cita: NOTA IMPORTANTE:
El uso de la librería mysql está desaconsejado, por lo que nos basaremos exclusivamente en mysql
i y PDO.
Más info:
http://www.forosdelweb.com/f18/anunc...ecada-1008145/
Si usas un motor de base de datos diferente de MySQL, revisa el manual de PHP para la librería correspondiente, donde encontrarás las funciones adecuadas para evitar ataques.
Por seguridad y para evitar errores, los datos a incluir en una consulta SQL deben ser "escapados" o "preparados".
Veamos la sintáxis de algunas consultas comunes:
Supongamos que 'Este valor es una cadena' lo enviamos por medio de la variable $cadena y que podemos obtener el valor a través de un formulario o de otra consulta a la base de datos, lo mismo para el número 5 usado en id.
Si los valores son como en el ejemplo, no tendremos problemas para ejecutar la consulta, pero, qué pasa si tenemos algo como:
Código PHP:
Ver original$cadena "Esta cadena contiene ' comilla simple";
$id = 'número';
Las consultas quedarían así:
Código MySQL:
Ver originalINSERT INTO tabla SET cadena = 'Esta cadena contiene ' comilla simple';
UPDATE tabla SET cadena = 'Este valor es una cadena' WHERE id = 'numero';
Este es el menos malo de los escenarios, porque al tratar de ejecutar la consulta sólo obtendremos un error de sintáxis porque:
- La comilla simple hace que termine el valor de cadena y lo que viene después es "basura" en la consulta
- 'número' no se puede asignar a id porque se trata de un campo numérico
Lo de la variable $id se puede solucionar fácilmente como vimos antes, forzando a que sea entero y validando, pero, si tenemos esto:
Código PHP:
Ver original$cadena = "cualquier cosa'; INSERT INTO usuarios (usuario, password, rol) VALUES ('Triby', 'contraseña', 'admin'); #";
La primera consulta UPDATE quedaría así (los saltos de línea son para verlo mejor):
1- Se ejecuta UPDATE estableciendo el valor de cadena en 'cualquier cosa' para todos los registros de la tabla, la comilla simple corta el contenido del campo.
2- El punto y coma le indica al motor de base de datos que finalizó la primera consulta y continúa otra.
3- Se ejecuta INSERT INTO, registrando al usuario, obteniendo permisos de administrador.
4- El punto y coma separa la siguiente consulta que, por el signo de número (#) es un comentario y no se ejecuta.
Algunas soluciones posibles con mysqli: NOTA: Mysqli por procedimientos también está considerado obsoleta, hay que usar orientado a objetos o PDO.
Código PHP:
Ver original// Recordar que previamente se deben limpiar todas las entradas
// Para evitar ataques XSS y caracteres no permitidos
$cadena = $_POST['cadena'];
// Usando mysqli estructurado
// addslashes() no es suficiente, mejor usamos la función nativa de la librería
$sql = "SELECT * FROM tabla WHERE cadena = '$cadena'";
// Usando mysqli orientado a objetos
$mysqli = new mysqli('localhost', 'usuario', 'contraseña', 'base_de_datos');
$cadena = $mysqli->real_escape_string($cadena);
$sql = "SELECT * FROM tabla WHERE cadena = '$cadena'";
$resultados = $mysqli->query($sql);
// Usando mysqli con consultas preparadas y parámetros enlazados
$mysqli = new mysqli('localhost', 'usuario', 'contraseña', 'base_de_datos');
$sql = "SELECT * FROM tabla WHERE cadena = ?";
$stmt = $mysqli->prepare($sql);
// Agregamos el valor de $cadena como string a la consulta preparada
$stmt->bind_param('s', $cadena);
$stmt->execute();
Hay otras opciones con mysqli y si requieres más info, ingresa en:
http://www.php.net/manual/es/book.mysqli.php Algunas soluciones posibles con PDO:
Código PHP:
Ver original// Recordar que previamente se deben limpiar todas las entradas
// Para evitar ataques XSS y caracteres no permitidos
$cadena = $_POST['cadena'];
// Info para conectar a MySQL
$dbhost = 'mysql:dbname=pruebas;host=localhost';
$dbuser = 'usuario';
$dbpass = 'contraseña';
// Establecer conexión y seleccionar base de datos
$db = new PDO($dbhost, $dbuser, $dbpass);
// Parámetros con nombre
$sql = "SELECT * FROM tabla WHERE cadena = :cadena";
$sth = $db->prepare($sql);
$sth->execute(array(':cadena' => $cadena));
// Parámetros con signo de interrogación
$sql = "SELECT * FROM tabla WHERE cadena = ?";
$sth = $db->prepare($sql);
$sth->execute(array($cadena));
// Enlazando parámetros
$sql = "SELECT * FROM tabla WHERE cadena = :cadena";
$sth = $db->prepare($sql);
$sth->bindParam(':cadena', $cadena, PDO::PARAM_STR, 50);
$sth->execute();
Como habrás podido notar, PDO con parámetros enlazados es la mejor opción, ya que te permite especificar el tipo y longitud del dato que se agregará a la consulta.
Hay otras opciones con PDO y si requieres más info, ingresa en:
http://www.php.net/manual/es/book.pdo.php Nota: Usando parámetros con nombre o con signo de interrogación, PDO trata todos los campos como cadenas.
-- Continuará --