¿Cómo puedo evitar la inyección SQL en PHP?
Si la entrada del usuario se inserta sin modificación en una consulta SQL, entonces la aplicación se vuelve vulnerable a la inyección SQL, como en el siguiente ejemplo:
$unsafe_variable = $_POST['user_input'];
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
Esto es porque el usuario puede introducir algo como value'); DROP TABLE table;--
, y la consulta se convierte en:
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
¿Qué se puede hacer para evitar que esto ocurra?
2776
3
Si está usando una versión reciente de PHP, la opción
mysql_real_escape_string
descrita a continuación ya no estará disponible (aunquemysqli::escape_string
es un equivalente moderno). Hoy en día la opciónmysql_real_escape_string
sólo tendría sentido para el código heredado en una versión antigua de PHP.Tiene dos opciones - escapar los caracteres especiales en su
unsafe_variable
, o usar una consulta parametrizada. Ambas te protegerán de la inyección SQL. La consulta parametrizada se considera la mejor práctica, pero requerirá cambiar a una extensión más reciente de MySQL en PHP antes de poder usarla.Cubriremos primero el escape de cadenas de menor impacto.
Ver también, los detalles de la función
mysql_real_escape_string
.Para utilizar la consulta parametrizada, es necesario utilizar MySQLi en lugar de las funciones MySQL. Para reescribir su ejemplo, necesitaríamos algo como lo siguiente.
La función clave que querrás leer ahí sería
mysqli::prepare
.También, como otros han sugerido, puedes encontrar útil/fácil subir una capa de abstracción con algo como PDO.
Ten en cuenta que el caso por el que preguntas es bastante sencillo y que casos más complejos pueden requerir enfoques más complejos. En particular:
mysql_real_escape_string
. En este tipo de casos, sería mejor pasar la entrada del usuario a través de una lista blanca para asegurar que sólo se permiten valores 'seguros'.mysql_real_escape_string
, sufrirás el problema descrito por Polynomial en los comentarios de abajo. Este caso es más complicado porque los enteros no estarían rodeados de comillas, por lo que se podría solucionar validando que la entrada del usuario contenga sólo dígitos.Yo recomendaría usar PDO (PHP Data Objects) para ejecutar consultas SQL parametrizadas.
Esto no sólo protege contra la inyección de SQL, sino que también acelera las consultas.
Y al usar PDO en lugar de las funciones
mysql_
,mysqli_
, ypgsql_
, hace que su aplicación sea un poco más abstracta de la base de datos, en el raro caso de que tenga que cambiar de proveedor de base de datos.Podrías hacer algo básico como esto:
Esto no resolverá todos los problemas, pero es un muy buen paso. He omitido elementos obvios como la comprobación de la existencia de la variable, el formato (números, letras, etc.).