sql >> Base de Datos >  >> RDS >> Mysql

¿Puedo usar una declaración preparada de PDO para vincular un identificador (una tabla o un nombre de campo) o una palabra clave de sintaxis?

¿Puedo usar una declaración preparada de PDO para vincular un identificador (una tabla o un nombre de campo) o una palabra clave de sintaxis?

Desafortunadamente, la declaración preparada solo puede representar un literal de datos. Entonces, una trampa muy común es una consulta como esta:

$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm  = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();

Depende de la configuración de PDO, esta consulta dará como resultado un error (en caso de usar declaraciones preparadas reales) o simplemente una cadena literal 'id' en el campo (en caso de preparaciones emuladas).

Por lo tanto, un desarrollador debe encargarse de los identificadores por sí mismo:PDO no ofrece ayuda para este asunto.

Para que un identificador dinámico sea seguro, se deben seguir 2 reglas estrictas:

  • para formatear correctamente el identificador
  • para verificarlo con una lista blanca codificada .

Para formatear un identificador, se deben aplicar estas 2 reglas:

  • Incluya el identificador en acentos graves.
  • Escapa de los acentos graves del interior duplicándolos.

Después de dicho formato, es seguro insertar la variable $tabla en la consulta. Entonces, el código sería:

$field = "`".str_replace("`","``",$field)."`";
$sql   = "SELECT * FROM t ORDER BY $field";

Sin embargo, aunque dicho formato sería suficiente para casos como ORDER BY, para la mayoría de los demás casos existe la posibilidad de un tipo diferente de inyección:permitir que un usuario elija una tabla o un campo que puede ver, podemos revelar algunos información confidencial, como contraseña u otros datos personales. Por lo tanto, siempre es mejor comparar los identificadores dinámicos con una lista de valores permitidos. He aquí un breve ejemplo:

$allowed = array("name","price","qty");
$key     = array_search($_GET['field'], $allowed);
$field   = $allowed[$key];
$query   = "SELECT $field FROM t"; //value is safe

Para las palabras clave, las reglas son las mismas, pero, por supuesto, no hay formato disponible; por lo tanto, solo es posible y debe usarse la lista blanca:

$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC'; 
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe

Consulte también esta nota aportada por el usuario en la documentación de PHP:Nota del usuario sobre PDO::quote