2011-04-27 12 views
17

que tenían esta discusión con una alta reputación chico PHP:¿Cómo prevenir la inyección SQL con nombres dinámicos de tablas?

PDO no tiene ningún uso aquí. así como mysql_real_escape_string. extremadamente mala calidad.

Esto, por supuesto, es fresco, pero, sinceramente, no sé qué le pasa a lo que sugiere el uso de mysql_real_escape_string o DOP para solucionar 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()); 

En este

$layer = mysql_real_escape_string($_GET['layer']); 
$query = "SELECT Category, COUNT(BUSNAME) 
FROM `".$layer."` GROUP BY Category"; 

, teniendo en cuenta que el código JavaScript se envía al lado del cliente.

+0

¿Alguien puede por favor publicar el código de ejemplo de cómo solucionar este agujero de inyección de SQL? – Johan

+0

@nikic Veo hacia dónde te diriges, pero no parece infalible :-) – Johan

+0

Sí, tampoco creo que sea infalible. El problema que veo es esta codificación relacionada con cosas, como mencioné en mi respuesta a continuación. Pero no tengo idea de cómo funcionan estos hacks basados ​​en codificación y, por lo tanto, no sé cómo prevenirlos. – NikiC

Respuesta

37

Su consejo es realmente incorrecto.

mysql_real_escape_string() no funcionará para nombres dinámicos de tablas; está diseñado para escapar datos de cadena , delimitados por las comillas, solamente. No escapará al personaje de atrás. Es una distinción pequeña pero crucial.

Así que podría insertar una inyección SQL en esto, solo tendría que usar un backtick de cierre.

PDO does not provide sanitation for dynamic table names, either.

Es por eso que es bueno no usar nombres dinámicos de tablas, o si es necesario, compararlos con una lista de valores válidos, como una lista de tablas de un comando SHOW TABLES.

Tampoco era realmente consciente de esto, y probablemente culpable de repetir el mismo mal consejo, hasta que me fue señalado aquí en SO, también por el Coronel Shrapnel.

+6

+1 Excelente respuesta. ¡Ciertamente, hoy aprendí algo nuevo! – Endophage

+3

+1 Esto es algo que he perdido durante mucho tiempo en PDO. Una cita 'PDO-> (..., PDO :: PARAM_IDENTIFIER)' o algo así. Esto a menudo disminuye el enfoque PDOs de DB cruzada, porque diferentes DB tienen citas diferentes y escapan para eso.En MySQL, con frecuencia utiliza el backtick y '" 'es solo una cita de identificador en el modo' ANSI', pero en otros DBMS '' 'es el camino a seguir. Hum, hum, hum :) – NikiC

+0

@nikic yeah! Esto es definitivamente una deficiencia de PDO. Yo tampoco lo entiendo. –

1

Con el fin de responder a cómo solucionar realmente el código:

'...FROM `' . str_replace('`', '``', $tableName) . '`...' 

Esto duplica todos los acentos abiertos en el nombre de tabla (así es como se escape en MySQL se realiza).

Una cosa de la que no estoy seguro es si esto es "seguro para la codificación" (¿cómo se llama correctamente?). Uno generalmente recomienda mysql_real_escape_string en lugar de addslashes, porque el primero toma en cuenta la codificación de la conexión MySQL. Quizás este problema se aplique aquí también.

+0

@nikic, esto no evitará usar 'table \' \ 'union select x, y from mysql.user' como un nombre de tabla – Johan

+0

@Johan: ¿Por qué no? Se insertará como: '... FROM \' table \ '\' \ '\' union select x, y from mysql.user \ '...' – NikiC

+0

así que omita los backticks e inyecte 'table ` union select x, y de mysql.user' – Johan

5

Para el registro, 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`"; 
} 
Cuestiones relacionadas