Cuando se trata de consultas a bases de datos, siempre intente utilizar consultas con parámetros preparados. Las bibliotecas mysqli
y PDO
son compatibles. Esto es infinitamente más seguro que usar funciones de escape como mysql_real_escape_string
.
Sí, mysql_real_escape_string
es efectivamente solo una función de escape de cadenas. No es una bala mágica. Todo lo que hará es escapar de los caracteres peligrosos para que puedan ser seguros de usar en una sola cadena de consulta. Sin embargo, si no desinfecta sus entradas de antemano, entonces será vulnerable a ciertos vectores de ataque.
Imagínese el siguiente SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
usted debería ser capaz de ver que esto es vulnerable a explotar.
Imagínese el parámetro id
contenía el vector de ataque común:
1 OR 1=1
No hay caracteres de riesgo en que hay que codificar, por lo que pasará directamente a través del filtro de escape. dejándonos:
SELECT fields FROM table WHERE id= 1 OR 1=1
que es un vector de inyección SQL precioso y permitiría al atacante para devolver todas las filas. O
1 or is_admin=1 order by id limit 1
que produce
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
que permite que el atacante se devuelven detalles de la primera de administrador en este ejemplo completamente ficticia.
Aunque estas funciones son útiles, deben utilizarse con cuidado. Debe asegurarse de que todas las entradas web estén validadas hasta cierto punto. En este caso, vemos que podemos ser explotados porque no verificamos que una variable que utilizamos como número sea en realidad numérica. En PHP se debe utilizar ampliamente un conjunto de funciones para comprobar que las entradas son números enteros, flotadores, etc. alfanumérica Pero cuando se trata de SQL, prestaron atención más el valor de la declaración preparada. El código anterior habría sido seguro si fuera una declaración preparada ya que las funciones de la base de datos habrían sabido que 1 OR 1=1
no es un literal válido.
En cuanto a htmlspecialchars()
. Ese es un campo de minas propio.
Hay un problema real en PHP, ya que tiene toda una selección de diferentes funciones de escape asociados con HTML, y sin una orientación clara sobre exactamente qué funciones lo hacen.
En primer lugar, si se encuentra dentro de una etiqueta HTML, que está en problemas reales.Miramos
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Ya estamos dentro de una etiqueta HTML, por lo que no necesitamos < o> para hacer algo peligroso. Nuestro vector de ataque podría ser sólo javascript:alert(document.cookie)
HTML resultante Ahora parece
<img src= "javascript:alert(document.cookie)" />
El ataque va directamente a través.
Se pone peor. ¿Por qué? porque htmlspecialchars
(cuando se llama de esta manera) solo codifica comillas dobles y no solo. Así que si tuviéramos
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Nuestro atacante mal que ahora puede inyectar parámetros enteros nuevos
pic.png' onclick='location.href=xxx' onmouseover='...
nos da
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
En estos casos, no hay una varita mágica, sólo hay que santise la entrada usted mismo. Si intentas filtrar los caracteres incorrectos, seguramente fallarás. Tome un enfoque de lista blanca y solo deje pasar los caracteres que son buenos. Mire XSS cheat sheet para ver ejemplos de cómo diversos vectores pueden ser
Incluso si usa htmlspecialchars($string)
fuera de las etiquetas HTML, sigue siendo vulnerable a los vectores de ataque de juego de caracteres de varios bytes.
Lo más eficaz que puede ser es utilizar una combinación de mb_convert_encoding y htmlentities de la siguiente manera.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Incluso esto deja IE6 vulnerable, debido a la forma en que maneja UTF. Sin embargo, podría recurrir a una codificación más limitada, como ISO-8859-1, hasta que el uso de IE6 disminuya.
Para un estudio más en profundidad de los problemas de varios bytes, ver https://stackoverflow.com/a/12118602/1820
Lo único que se echa de menos aquí, es que el primer ejemplo para la consulta DB ... un simple intval() resolvería la inyección. Siempre use intval() en lugar de mysqlescape ...() cuando necesite un número y no una cadena. –
y recuerde que el uso de consultas parametrizadas le permitirá tener siempre datos tratados como datos y no como código. Use una biblioteca como PDO y use consultas parametrizadas siempre que sea posible. – Cheekysoft
¡Excelente respuesta! – joedevon