¿Cómo puedo evitar la inyección de SQL con nombres de tablas dinámicos?

Resuelto Johan asked hace 54 años • 3 respuestas

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_stringo 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.

Johan avatar Jan 01 '70 08:01 Johan
Aceptado

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 TABLEScomando.

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.

Pekka avatar Apr 27 '2011 23:04 Pekka

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`";
}
 avatar May 18 '2011 21:05

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_stringen 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í.

NikiC avatar Apr 27 '2011 23:04 NikiC