2011-01-26 2 views
6

El pienso es que tengo un sitio web completo de trabajo con muchas llamadas al servidor MySQL y hacer algunas investigaciones en este sitio vi que hacer mis querys en esta forma:Prevención de inyección SQL utilizando SOLO php

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'", 
      mysql_real_escape_string($user), 
      mysql_real_escape_string($password)); 

Puedo resolver el problema de seguridad, pero, como dije, tengo muchas llamadas al servidor MySQL, y la mejor manera (en mi caso) para resolver el problema es ir directamente a los vars que paso a la consulta, pero sin usar una Función MySQL porque estoy fuera de la consulta. Me explico, tengo esto:

mysql_query("SELECT * FROM `post` WHERE id=" . $_GET['edit']); 

no puedo hacer modificaciones a esta consulta porque tengo un montón de esto en toda mi código, insted i preefer para comprobar si las inyecciones en el var, $ _GET [' editar'].

¿Cómo puedo usar cheque PHP puro para inyecciones SQL en las variables de los querys? Me gusta:

$_GET['edit']=freehack($_GET['edit']); 
+1

Viendo el número de personas votadas y preferidas * esto, * ¡No puedo creer que haya tantos desarrolladores tan pobres por aquí! Entonces, ¿todas estas personas tienen el mismo problema y buscan el * mismo tipo de solución? –

+0

Además, será mejor que no escape su contraseña afaik. Cifre la contraseña si va a usarla para comparar. – Nick

+3

"No puedo hacer modificaciones en esta consulta porque tengo mucho de esto en todo mi código" La pereza es impropia frente a un error grave. – Andrew

Respuesta

12

No lo hagas de esta manera. Al reemplazar el valor de sus parámetros $_GET por versiones "seguras", está contaminando sus datos de entrada, que puede necesitar para otros lugares.

Solo escapa datos cuando necesita usarlos en la capa de la base de datos. Solo le llevará un poco de tiempo arreglar sus consultas y le ahorrará un montón de dolores de cabeza a largo plazo.

En cualquier caso, lo que está haciendo todavía no es seguro! Ver: PHP: Is mysql_real_escape_string sufficient for cleaning user input?

Realmente debería utilizar prepared queries with PDO. Además, debe verificar la validez de su entrada de usuario antes de usarla en una consulta.

+0

Para resumir: al escanear cadenas, use mysql_real_escape_string(). Al escaparse enteros, use intval(). – TehShrike

+0

'debe verificar la validación de la entrada de su usuario antes de usarlo en una consulta' es una parte importante que las personas a veces olvidan. Si esperas un número entero, ¿por qué no estás comprobando si se trata de un número entero en lugar de tratar de incluir algo en la consulta? – HoLyVieR

+0

@TehShrike cuando escapa de identificadores, use la lista blanca –

7

"No puedo hacer modificaciones a esta consulta porque tengo un montón de esto en toda mi código" es la actitud equivocada cuando se habla de seguridad. Lo que tienes allí es un problema de diseño importante que te abre a todo tipo de problemas de seguridad. Incluso si hace algo así como el método de filtro que describe al final, no puede estar seguro de que cubrirá todos los casos.

Usted realmente debe utilizar algún tipo de clase de acceso de base de datos para consultar la base de datos en lugar de hacer llamadas al azar de este tipo en todo el código. De esta forma, puede escribir el código de desinfección una vez y puede estar absolutamente seguro de que se lo llama a todas partes. La refactorización vale la pena por la seguridad adicional que obtendrá.

0

No iría con una función "mágica" y espero que limpie las variables. Esto no resolverá todos los casos extremos y seguirá siendo vulnerable.

Un buen ejemplo de esto es su segunda consulta. Todavía es vulnerable a la inyección SQL incluso si mysql_real_escape_string la variable $_GET['edit'].

Lo que hay que hacer es validar todos los datos que recibe y comprueba si es el tipo de datos esperados.

if (SomeValidator::validateInt($_GET['edit'])) { 
    // OK, we continue // 
} else { 
    // Display error, but don't continue ! // 
} 

Desinfección solo está allí asegúrese de que los datos se mostrarán correctamente y no causarán ningún problema. No debe confiar en la desinfección para la validación de sus datos.

Si desea obtener la validación y la desinfección se hace bien se puede utilizar el ESAPI for PHP.

0

Recomendaría utilizar la interfaz PDO, o la interfaz MySQLi, ya que ambas soportan el uso de consultas preparadas. El uso de consultas preparadas es la única manera de protegerse eficaz y sistemáticamente de nuevo los ataques de inyección de SQL. Personalmente recomiendo PDO sobre mysqli ya que proporciona una interfaz de base de datos independiente para su base de datos, en caso de que alguna vez necesite cambiar las bases de datos. Incluso si nunca necesita cambiar las bases de datos, es mejor que solo tenga que aprender 1 interfaz, en caso de que necesite trabajar en otro proyecto usando una base de datos diferente.

0
  1. evitar que la misma consulta repetida en diferentes lugares a través de su aplicación - a medida que crecen las cosas tiene varias versiones para mantener y que casi invariablemente perder la sincronización. Las consultas preparadas me suenan bien (no soy realmente un tipo de PHP), o si tiene que ir de otra manera, configure una biblioteca de referencia central y almacene sus consultas allí, luego hágase referencia cuando las necesite en su aplicación.

  2. No almacene datos codificados, es muy fácil olvidar qué variables están codificadas y cuáles no, además de que terminará en problemas tan pronto como tenga que usar sus datos para un propósito con una codificación diferente. Codifique lo más tarde posible en el proceso, idealmente cuando se lo coloca en la situación final donde necesita codificación para que una inspección rápida pueda mostrar que se está realizando.

  3. Si tiene que ... SQL Injection es significativamente un problema de seguridad de tipo. Si sabe que está esperando un parámetro entero, "1; drop table users; -" no es una entrada válida aunque no contenga ningún carácter peligroso o escape de secuencias. No se limite a revisar si se trata de cadenas o lo que sea, asegúrese de que cuando desee un tipo específico, obtenga esa y otra entrada que arroje un error.

1

Creo que podría ajustar su consulta dentro de PDO.

$unsafe = "SELECT * FROM `post` WHERE id=" . $_GET['edit']; 
$DBH->quote($unsafe); // makes query safe. 

donde $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);

entonces usted tiene que escribir algún tipo de secuencias de comandos para hacer el nuevo replacements.Then Realmente cree que debería volver a escribir el código desde cero, ya que es muy feo. Pruebas unitarias correctas, PDO, protección CSRF, OOP, etc.

Cuestiones relacionadas