¿Cómo puedo evitar la inyección de SQL con nombres de tablas dinámicos?
Tuve esta discusión con un chico de PHP de gran reputación:
La DOP no sirve aquí. así como mysql_real_escape_string. calidad extremadamente mala.
Esto, por supuesto, es genial, pero honestamente no sé qué hay de malo en sugerir el uso de mysql_real_escape_string
o PDO para corregir este código:
<script type="text/javascript">
var layer;
window.location.href = "example3.php?layer="+ layer;
<?php
//Make a MySQL connection
$query = "SELECT Category, COUNT(BUSNAME)
FROM ".$_GET['layer']." GROUP BY Category";
$result = mysql_query($query) or die(mysql_error());
Dentro de esto
$layer = mysql_real_escape_string($_GET['layer']);
$query = "SELECT Category, COUNT(BUSNAME)
FROM `".$layer."` GROUP BY Category";
, considerando que el código JavaScript se envía del lado del cliente.
De hecho, tu consejo es incorrecto.
mysql_real_escape_string()
no funcionará para nombres de tablas dinámicas; está diseñado para escapar de datos de cadena, delimitados únicamente por comillas. No escapará del carácter de comilla invertida. Es una distinción pequeña pero crucial.
Para poder insertar una inyección SQL en esto, solo tendría que usar una comilla invertida de cierre.
PDO tampoco proporciona saneamiento para nombres de tablas dinámicas .
Por eso es bueno no utilizar nombres de tablas dinámicas o, si es necesario, compararlos con una lista de valores válidos, como una lista de tablas de un SHOW TABLES
comando.
En realidad, tampoco era plenamente consciente de esto, y probablemente era culpable de repetir el mismo mal consejo, hasta que me lo señaló aquí en SO, también por el Coronel Shrapnel.
Para que conste, aquí hay un código de muestra para arreglar este agujero.
$allowed_tables = array('table1', 'table2');
$clas = $_POST['clas'];
if (in_array($clas, $allowed_tables)) {
$query = "SELECT * FROM `$clas`";
}
Para responder cómo arreglar realmente el código:
'...FROM `' . str_replace('`', '``', $tableName) . '`...'
Esto duplica todas las comillas invertidas en el nombre de la tabla (así es como se realiza el escape en MySQL).
Una cosa de la que no estoy seguro es si esto es "codificación segura" (¿cómo se llama correctamente?). Normalmente se recomienda mysql_real_escape_string
en lugar de addslashes
, porque el primero tiene en cuenta la codificación de la conexión MySQL. Quizás este problema también se aplique aquí.