2009-02-11 28 views
31

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.¿Cuándo * no * usar declaraciones preparadas?

Parecía natural reemplazar estas funciones ad-hoc con un objeto que usa PDO y declaraciones realmente preparadas, pero después de leerlas, 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 todas trivialmente simples. La mayoría tiene el formato SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1. La afirmación más compleja del lote es simplemente tres selecciones unidas junto con UNION ALL s.
  • Cada visita a la página ejecuta a lo sumo una declaración y la ejecuta solo una vez.
  • Estoy en un entorno alojado y, por lo tanto, receloso de cerrar de golpe sus servidores realizando personalmente "pruebas de resistencia".

Dado que el uso de declaraciones preparadas duplicará, como mínimo, el número de viajes de ida y vuelta a la base de datos que hago, ¿será mejor que los evite? ¿Puedo usar PDO::MYSQL_ATTR_DIRECT_QUERY para evitar la sobrecarga de múltiples viajes a la base de datos mientras se 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?

EDIT:

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. Al final, sin embargo, tengo que dar el rick a su debido ... sin su respuesta me habría ido felizmente y habría hecho completamente lo incorrecto incluso después de siguiendo el consejo de de todos. :-)

Declaraciones preparadas emuladas es!

+3

** Tenga cuidado **: las instrucciones preparadas emuladas de PDO son vulnerables a la inyección de SQL si el conjunto de caracteres se modifica en tiempo de ejecución. Consulte [esta respuesta] (http://stackoverflow.com/a/60496/1862009) y [esta respuesta] (http://stackoverflow.com/a/12202218/1862009) para obtener una explicación. – toxalot

+0

Es fácil: si * sabe * que la cadena proviene de su aplicación y no puede ser manipulada por un usuario, entonces no hay necesidad de declaraciones preparadas, porque no hay nada que inyectar. Si no está seguro (mal, pero en proyectos mayores no evitables) use una declaración preparada. –

Respuesta

14

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.

24

La regla de hoy de la ingeniería de software: si no va a hacer nada por usted, no lo use.

+5

+5 - Personalmente, creo que la presión para * siempre * usar declaraciones preparadas huele a programación de culto a la carga. – toxalot

2

Honestamente, no creo que deba preocuparse 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.

He tenido el mismo problema que usted y yo tenía mis propias reservas, así que en vez de usar PDO terminé escribiendo mi propia capa de base de datos liviana que soporta preparaciones y declaraciones estándar y realicé escapes correctos (sql-injection prevención) 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 decirle qué otras opciones tiene 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.

7

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.

7

Los beneficios de las declaraciones preparadas son las siguientes:

  • cada consulta sólo se compila una vez
  • MySQL utilizará un formato de transporte más eficiente para enviar los 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.

+1

Olvidaste una: cotización inteligente de los datos que se le pasaron. – Powerlord

+6

Se perdió uno, pero no ese. Los parámetros de las declaraciones preparadas se pasan al servidor de base de datos a través de un canal separado (es decir, no como parte de una declaración de SQL), por lo que no necesitan ser escapados en absoluto porque están entrando explícitamente como datos, no como comando potencial. –

+1

No cambia nada en términos de eficiencia, o es un poco peor. SQL está compilado en el servidor, no en el cliente.Por lo tanto, cuando envía una declaración preparada con parámetros vinculados, en realidad envía múltiples paquetes al servidor (uno para la estadística de preparación, otra para los parámetros), por lo que agrega latencia. Sin embargo, si reutiliza su declaración de preparación, es una ganancia porque guarda el tiempo de compilación para la declaración y solo paga la penalización por enviar los parámetros. – xryl669

14

¿Cuándo no utilizar declaraciones preparadas? Cuando solo va a ejecutar la declaración una vez antes de que la conexión db desaparezca.

Cuando no usa 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 apuesto a que proporciona un mecanismo para ejecutar consultas parametrizadas con los valores proporcionados en la misma llamada a función si no desea prepararse, luego ejecútelo como un paso separado. (Por ejemplo, Algo así como run_query("SELECT * FROM users WHERE id = ?", 1) o similar.)

Además, si mira debajo del capó, la mayoría de las capas de abstracción de db prepararán la consulta y la ejecutarán, incluso si solo le indica 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.

Cuestiones relacionadas