statement - sentencias preparadas php mysqli
¿Cuándo*no*usar declaraciones preparadas? (6)
Estoy rediseñando un sitio web impulsado por PHP que utiliza una base de datos mínima. La versión original utilizaba "declaraciones pseudopreparadas" (funciones de PHP que incluían el reemplazo de parámetros y citas) para evitar ataques de inyección y separar la lógica de la base de datos de la lógica de la página.
Parecía natural reemplazar estas funciones ad-hoc con un objeto que usa PDO y declaraciones realmente preparadas, pero después de leer sobre ellas, no estoy tan seguro. PDO todavía parece una gran idea, pero uno de los principales puntos de venta de declaraciones preparadas es poder reutilizarlas ... lo que nunca haré. Aquí está mi configuración:
- Las declaraciones son trivialmente simples. La mayoría están en la forma
SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1
SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1
. La declaración más compleja en el lote es simplemente tres selecciones unidas conUNION ALL
s. - Cada hit de página ejecuta como máximo una sentencia y la ejecuta solo una vez.
- Estoy en un entorno alojado y, por lo tanto, receloso de cerrar sus servidores haciendo personalmente "pruebas de estrés".
Dado que el uso de declaraciones preparadas duplicará, como mínimo, el número de viajes de ida y vuelta que hago en la base de datos, ¿será mejor que los evite? ¿Puedo usar PDO::MYSQL_ATTR_DIRECT_QUERY
para evitar la sobrecarga de múltiples viajes de bases de datos a la vez que conserva el beneficio de la parametrización y la defensa de inyección? ¿O las llamadas binarias utilizadas por la API de declaración preparada funcionan bastante bien en comparación con la ejecución de consultas no preparadas que no debería preocuparme por ello?
EDITAR:
Gracias por todos los buenos consejos, amigos. Este es uno en el que me gustaría poder marcar más de una respuesta como "aceptada", muchas perspectivas diferentes. Sin embargo, en última instancia, tengo que darle a rick lo que me corresponde ... sin su respuesta me habría ido felizmente y habría hecho algo completamente incorrecto incluso después de seguir los consejos de todos. :-)
¡Declaraciones preparadas emuladas es!
¿Cuándo no usar declaraciones preparadas? Cuando solo va a ejecutar la declaración una vez antes de que la conexión db desaparezca.
¿Cuándo no usar los parámetros de consulta enlazados (que es realmente lo que la mayoría de la gente usa declaraciones preparadas para obtener)? Me inclino a decir "nunca" y realmente me gustaría decir "nunca", pero la realidad es que la mayoría de las bases de datos y algunas capas abstractas de db tienen ciertas circunstancias en las que no le permitirán vincular parámetros, por lo que se ven obligados a no usarlos en esos casos. En cualquier otro momento, sin embargo, hará que su vida sea más simple y su código más seguro para usarlos.
No estoy familiarizado con PDO, pero apostaría a que proporciona un mecanismo para ejecutar consultas parametrizadas con los valores proporcionados en la misma llamada a función si no desea prepararse, y luego ejecutarlo como un paso separado. (Por ejemplo, algo como run_query("SELECT * FROM users WHERE id = ?", 1)
o similar.)
Además, si miras debajo del capó, la mayoría de las capas de abstracción de db prepararán la consulta y luego la ejecutarán, incluso si solo le dices que ejecute una instrucción SQL estática. Por lo tanto, probablemente no estés guardando un viaje a la base de datos evitando de todos modos los preparativos explícitos.
Creo que quieres PDO :: ATTR_EMULATE_PREPARES. Eso desactiva las declaraciones preparadas de bases de datos nativas, pero aún permite enlaces de consulta para evitar la inyección de sql y mantener ordenada su sql. Por lo que entiendo, PDO :: MYSQL_ATTR_DIRECT_QUERY desactiva por completo los enlaces de consulta.
Honestamente, no creo que debas preocuparte por eso. Sin embargo, recuerdo que varios marcos de acceso a datos de PHP admitían modos de declaración de preparación y modos de declaración de no preparación. Si mal no recuerdo, PEAR: DB lo hizo en el día.
Me encontré con el mismo problema que usted y yo tenía mis propias reservas, así que en lugar de usar PDO, terminé escribiendo mi propia capa de base de datos liviana que admitía preparaciones y declaraciones estándar y realicé el escape correcto (prevención de inyección sql) en ambos casos. Una de mis otras quejas con los prepares es que a veces es más eficiente agregar alguna entrada no escapible a una declaración como ... DONDE id IN (1, 2, 3 ...).
No sé lo suficiente sobre PDO para decirte qué otras opciones tienes para usarlo. Sin embargo, sí sé que PHP tiene funciones de escape disponibles para todos los proveedores de bases de datos que admite y usted puede rodar su propia pequeña capa sobre cualquier capa de acceso a datos con la que se encuentre.
Las declaraciones preparadas están siendo utilizadas por miles de personas y, por lo tanto, están bien probadas (y, por lo tanto, se puede inferir que son razonablemente seguras). Su solución personalizada solo la usa usted.
La probabilidad de que su solución personalizada sea insegura es bastante alta. Use declaraciones preparadas. Tienes que mantener menos código de esa manera.
Los beneficios de las declaraciones preparadas son los siguientes:
- cada consulta solo se compila una vez
- mysql usará un formato de transporte más eficiente para enviar datos al servidor
Sin embargo, las declaraciones preparadas solo persisten por conexión. A menos que esté usando la agrupación de conexiones, no habría beneficio si solo está haciendo una declaración por página. Las consultas trivialmente simples tampoco se beneficiarían del formato de transporte más eficiente.
Personalmente, no me molestaría. Es probable que las declaraciones pseudopreparadas sean útiles para la variable segura que presuntamente brindan.
La regla de hoy de la ingeniería de software: si no va a hacer nada por usted, no la use.