2012-08-14 36 views
7

Estoy haciendo una pequeña aplicación web que recibirá datos ingresados ​​por los usuarios regularmente. Al investigar cómo asegurarse de que la entrada de datos se depure primero, y para que parezca que las declaraciones preparadas son el camino a seguir.¿Cómo enlazar parámetros a una consulta que no está preparada?

He encontrado this SO question sin embargo, y como mi aplicación (al menos hasta donde yo sé) no hará más de una consulta por solicitud de página, parece que todo lo que realmente necesito es la vinculación de valores a parámetros en la consulta.

He estado buscando en el manual de PHP en PDO y mysqli, pero no puedo encontrar ningún ejemplo donde los valores están vinculados a una consulta normal. Todos los ejemplos que he encontrado tienen un $stmt->prepare en algún lugar antes del enlace.

¿Es que la declaración está "preparada" o no algo que está determinado por el soporte de la base de datos, y la declaración de preparación siempre estará en el código? ¿O hay una forma de enlazar parámetros directamente en un $dbh->query(...)?

Para explicar por qué estoy mirando a ver si es posible no utilizar preparar, se debe a esta declaración de la pregunta SO he vinculado anteriormente en el mensaje:

Cuando no usar comandos preparados? Cuando solo va a ejecutar la declaración una vez antes de que la conexión db desaparezca.

Cuando no se usan los parámetros de consulta enlazados (que es realmente lo que la mayoría de la gente usa declaraciones preparadas para obtener)

y esto

En lo personal no me molestaría. Es probable que las declaraciones pseudopreparadas sean útiles para la variable segura que presuntamente brindan.

+0

¿Puedes explicar * por qué * quieres omitir 'prepare()'? – Tomalak

+0

¿Por qué las personas menosprecian sin dar una razón? Era otra pregunta en este sitio que me llevó a creer que había una distinción entre los dos en primer lugar. – sicks

Respuesta

4

¿Cómo enlazar los parámetros a una consulta que no está preparada?

Usted no lo hace. Una cadena SQL con parámetros (es decir, signos de interrogación en lugares específicos) debe analizarse (es decir, preparada) antes de que esos signos de interrogación se puedan tratar como puntos de inserción para valores de parámetros. Por favor, siempre debe llamar al prepare() para llamar al bind().


Un parametrizado comunicado es una cadena que contiene marcadores de SQL y marcador de posición (por marcas ejemplo de pregunta, pero diferentes bases de datos utilizan diferentes marcadores de posición):

$sql = "SELECT user_id FROM user WHERE user_name = ?" 

Supongamos ahora que hay un valor se desea insertar en esta ubicación:

$_POST["username"] 

Preparar una declaración, en términos generales, da a los signos de interrogación su significado especial "aquí se puede insertar un valor".En otras palabras, crea parámetros de los marcadores de posición.

$stmt->prepare($sql) 

Encuadernación un valor a un parámetro establece el parámetro a un valor específico.

$stmt->bind_param("s", $_POST["username"]) 

Ahora la consulta se puede ejecutar sin la cadena SQL y el valor suministrado por el usuario en realidad nunca entren en contacto unos con otros. Este es el bit importante: Los valores de parámetros y SQL se envían al servidor por separado. Nunca se tocan.

$stmt->execute(); 

Las ventajas son:

  • puede enlazar un nuevo valor para el parámetro y ejecutar la consulta de nuevo sin tener que repetir todos de la misma (útil en un bucle).
  • La inyección SQL es imposible, no importa qué valor tenga $_POST["username"].
+0

Entonces, ¿no hay diferencia entre las declaraciones preparadas y los parámetros de consulta enlazados? (en términos de qué código escribo) – sicks

+0

@sicks Uhm, ¿qué te hace pensar eso? Ver respuesta modificada. – Tomalak

2

You Do not not. He aquí por qué:

Si usa $dbh->query(...) puede simplemente llamar a sql con los parámetros interpolados en la cadena sql. Mediante el uso de una consulta como

$dbh->query("INS INTO MY_TABLE_OF_NAMES ('$name');"); 

Hace unos 10 años, así es como se realizó la mayoría de sql. Esta es la manera más directa de invocar la base de datos, utilizando la interfaz SQL ya implementada por el RDMS, sin la necesidad de una interfaz especial de nivel inferior. Pero la gente descubrió que esto era peligroso debido a algo llamado inyección sql.

http://en.wikipedia.org/wiki/Sql_injection

El ejemplo más simple y más común es algo como esto. Supongamos que tenemos una llamada SQL en su página web que se ejecute:

INS INTO MY_TABLE_OF_NAMES VALUE ('$name'); 

Pero entonces alguien vendría a su sitio y entrar allí nombrar como bob'); DROP TABLE MY_TABLE_OF_NAMES;

repente la instrucción SQL interpolada se convierte en

INS INTO MY_TABLE_OF_NAMES VALUE ('bob'); DROP TABLE MY_TABLE_OF_NAMES;); 

que posteriormente insertaría bob en su base de datos, borrará todos sus nombres y arrojará un error para el ); posterior cuando su sitio web lo ejecutó.

Por lo tanto, se inventaron declaraciones preparadas. En lugar de interpolar cadena directamente en sus cadenas, usará caracteres ? para denotar valores dinámicos, y se usa una función bind para insertar la cadena de forma segura. De esta forma, el motor de la base de datos nunca interpretará la entrada de datos manejable como código SQL y su sitio no puede ser engañado para hacer cosas que no quiere hacer. El comando de preparación toma una cadena sql toma un poco de sql y semi compila en un langauge de base de datos de nivel inferior dejando espacios abiertos de cadenas dinámicas donde se usa ?. Bind luego toma uno de esos espacios abiertos y lo llena con un dato, codificado para ascii escapado, para que no pueda malinterpretarse como código SQL. Una vez que se llenan todos esos ? s, el sql está listo para ser enviado al RDMS para ser ejecutado.

Para responder a su pregunta, nunca vinculará un parámetro a una consulta simple. Si desea valores dinámicos en una consulta simple, simplemente interpolarlos en la cadena SQL. Pero esto es peligroso. Las declaraciones preparadas le permiten precompilar una declaración sql y luego vincular de forma segura los parámetros dinámicos para crear SQL dinámico y seguro. La vinculación a sql es puramente una construcción de enunciados preparados.

+0

+1 para su última frase. Esta fue prácticamente la confirmación que estaba buscando. Desearía poder establecer dos respuestas correctas – sicks

0

Para usar parámetros vinculados, debe usar declaraciones preparadas. Esta es la forma en que las cosas se implementan actualmente en pdo y mysqli. No estoy seguro si ciertos productos de bases de datos admiten algún tipo de protocolo de comunicación donde se envía el sql parametrizado (texto sql que usa marcadores de posición) junto con los valores de los parámetros sin tener que hacer primero una llamada de preparación explícita, pero pdo y mysqli no exponen esta funcionalidad si está disponible. Seguramente sería una característica bienvenida para las aplicaciones web.

Con pdo, sí, si el enunciado sql realmente se prepara cuando se llama al $dbh->prepare($sql) depende del soporte de la base de datos. El pdo emulará las declaraciones preparadas cuando la base de datos no las soporte, o siempre puede emularlas si está configurado para hacerlo. De hecho, pdo emula las declaraciones preparadas para el controlador mysql de forma predeterminada, y lo ha hecho de forma predeterminada durante mucho tiempo. Los emula creando sql dinámico, citando los valores, tal como lo haría. En este caso, el sql (con los valores finales incrustados en el texto) se envía a la base de datos cuando se llama al $stmt->execute(). Sí, la inyección sql es posible aquí bajo ciertos escenarios.

Cuestiones relacionadas