Si la entrada del usuario se inserta sin modificación en una consulta SQL, la aplicación se vuelve vulnerable a La inyección de SQLcomo en el siguiente ejemplo:

$unsafe_variable = $_POST['user_input']; 

mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");

Eso es porque el usuario puede introducir algo como value'); DROP TABLE table;--y la consulta se convierte en:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')

¿Qué se puede hacer para evitar que esto suceda?

OriginalEl autor |

28 Comentarios

  1. Uso de declaraciones preparadas y consultas parametrizadas. Estas son las instrucciones SQL que son enviados y leídos por el servidor de base de datos por separado de los parámetros. De esta manera es imposible que un atacante inyectar SQL malicioso.

    Básicamente tienes dos opciones para lograr esto:

    1. Utilizando PDO (para cualquier controlador de base de datos):

      $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
      
      $stmt->execute(array('name' => $name));
      
      foreach ($stmt as $row) {
          //do something with $row
      }
    2. Utilizando MySQLi (para MySQL):

      $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
      $stmt->bind_param('s', $name); //'s' specifies the variable type => 'string'
      
      $stmt->execute();
      
      $result = $stmt->get_result();
      while ($row = $result->fetch_assoc()) {
          //do something with $row
      }

    Si se está conectando a una base de datos distinta de MySQL, es un controlador específico de la segunda opción que puede referirse a (por ejemplo, pg_prepare() y pg_execute() para PostgreSQL). PDO es la opción universal.

    Configurar correctamente la conexión

    Tenga en cuenta que cuando se utiliza PDO para acceder a una base de datos MySQL real declaraciones preparadas son no se utiliza por defecto. Para solucionar esto tienes que desactivar la emulación de declaraciones preparadas. Un ejemplo de creación de una conexión utilizando PDO es:

    $dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
    
    $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    En el ejemplo anterior, el modo de error no es estrictamente necesario, pero se aconseja de añadir. De esta manera la secuencia de comandos no se detiene con un Fatal Error cuando algo va mal. Y le da a los desarrolladores la oportunidad de catch cualquier error(s) que se thrown como PDOExceptions.

    Lo que es obligatoriosin embargo, es la primera setAttribute() línea, que dice PDO para deshabilitar emulado declaraciones preparadas y uso real declaraciones preparadas. Esto asegura que la declaración y los valores no son interpretado por PHP antes de enviarlos al servidor de MySQL (dándole un posible atacante que no hay oportunidad para inyectar SQL malicioso).

    Aunque puede establecer el charset en las opciones del constructor, es importante tener en cuenta que los ‘mayores’ en versiones de PHP (< 5.3.6) omite el parámetro charset en el DSN.

    Explicación

    Lo que pasa es que la instrucción SQL que se pasa a prepare se analiza y compila el servidor de base de datos. Mediante la especificación de parámetros (ya sea un ? o el nombre de un parámetro como :name en el ejemplo anterior) puede decirle al motor de base de datos donde desea filtrar. Entonces, cuando usted llame executeel comunicado se combina con los valores de los parámetros que especifique.

    La cosa importante aquí es que los valores de los parámetros se combinan con el compilado de la declaración, no una cadena SQL. La inyección de SQL obras de engañar a la secuencia de comandos en incluyendo malicioso cadenas cuando se crea SQL para enviar a la base de datos. Así, mediante el envío de la real de SQL por separado a partir de los parámetros, se puede limitar el riesgo de acabar con algo que no tenía la intención. Cualquier parámetro que se envía cuando se utiliza una instrucción preparada acaba de ser tratados como cadenas (aunque el motor de base de datos puede hacer en la optimización de parámetros pueden terminar como los números también, por supuesto). En el ejemplo anterior, si el $name variable contiene 'Sarah'; DELETE FROM employeesel resultado podría ser simplemente una búsqueda de la cadena "'Sarah'; DELETE FROM employees"y usted no va a terminar con una tabla vacía.

    Otro de los beneficios de la utilización de declaraciones preparadas es que si ejecutan la misma instrucción muchas veces en la misma sesión sólo se analiza y compila una vez, que le da algo de velocidad ganancias.

    Oh, y ya que usted me preguntó sobre cómo hacerlo para una inserción, he aquí un ejemplo (usando PDO):

    $preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
    
    $preparedStatement->execute(array('column' => $unsafeValue));

    Puede declaraciones preparadas ser utilizado para la dinámica de las consultas?

    Mientras que usted todavía puede utilizar sentencias preparadas para los parámetros de la consulta, la estructura de la dinámica de la consulta en sí no se puede parametrizar y ciertas características de la consulta no puede ser parametrizado.

    Para estas situaciones específicas, la mejor cosa a hacer es utilizar un filtro de lista blanca que restringe los valores posibles.

    //Value whitelist
    //$dir can only be 'DESC' otherwise it will be 'ASC'
    if (empty($dir) || $dir !== 'DESC') {
       $dir = 'ASC';
    }
    Sólo para agregar porque no me veo en ningún otro lugar aquí, otra línea de defensa es un firewall de aplicaciones web (WAF) que puede hacer que las reglas se establecen para buscar ataques de inyección de sql:
    También, la documentación oficial de la mysql_query sólo permite ejecutar una consulta, para cualquier otra consulta, además ; se ignora. Incluso si esto ya es obsoleto, hay una gran cantidad de sistemas en PHP 5.5.0 y que pueden hacer uso de esta función. php.net/manual/en/function.mysql-query.php
    Este es un mal hábito, sino que es un post-solución de problema : No sólo para la inyección de SQL, pero para cualquier tipo de inyecciones (por ejemplo hubo una plantilla de vista de inyección agujero en F3 framework v2) si tienes una vieja sitio web o la aplicación está sufriendo de inyección de defectos , una solución es para reasignar los valores de su supperglobal predefinidos vars como $_POST con escapó a valores de bootstrap. Por PDO, todavía es posible para escapar (también para el día de hoy marcos) : substr($pdo->cotización($str, \PDO::PARAM_STR), 1, -1)
    Esta respuesta carece de la explicación de lo que es una declaración preparada – una cosa – es un impacto en el rendimiento si se utiliza una gran cantidad de declaraciones preparadas durante su solicitud y, a veces, se representa 10 veces el rendimiento. Mejor caso sería usar PDO con el parámetro de rem, pero la declaración de la preparación.
    Usando PDO es mejor, en caso de que usted está usando consulta directa asegúrese de usar mysqli::escape_string

    OriginalEl autor

  2. Advertencia:
    Esta respuesta es el código de ejemplo (como la cuestión del código de ejemplo) utiliza PHP MySQL extensión, que estaba en desuso en PHP 5.5.0 y eliminado completamente en PHP 7.0.0.

    Si usted está utilizando la versión más reciente de PHP, el mysql_real_escape_string opción describen a continuación dejará de estar disponible (aunque mysqli::escape_string es un equivalente moderno). En estos días la mysql_real_escape_string opción sólo tendría sentido para el código de la herencia en una versión anterior de PHP.


    Tienes dos opciones: escapar los caracteres especiales en su unsafe_variableo mediante una consulta parametrizada. Ambos se protegen de la inyección de SQL. La consulta parametrizada se considera la mejor práctica, pero se requiere el cambio a una nueva extensión de MySQL en PHP antes de poder usarlo.

    Vamos a cubrir el menor impacto en la cadena de escapar de uno de los primeros.

    //Connect
    
    $unsafe_variable = $_POST["user-input"];
    $safe_variable = mysql_real_escape_string($unsafe_variable);
    
    mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
    
    //Disconnect

    Ver también, los detalles de la mysql_real_escape_string función.

    El uso de la consulta con parámetros, es necesario utilizar MySQLi en lugar de la MySQL funciones. A reescribir su ejemplo, tendríamos algo como lo siguiente.

    <?php
        $mysqli = new mysqli("server", "username", "password", "database_name");
    
        //TODO - Check that connection was successful.
    
        $unsafe_variable = $_POST["user-input"];
    
        $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");
    
        //TODO check that $stmt creation succeeded
    
        //"s" means the database expects a string
        $stmt->bind_param("s", $unsafe_variable);
    
        $stmt->execute();
    
        $stmt->close();
    
        $mysqli->close();
    ?>

    La tecla de función que usted querrá leer hasta ahí sería mysqli::prepare.

    También, como otros han sugerido, usted puede encontrar que es útil/fácil paso una capa de abstracción con algo como PDO.

    Por favor, tenga en cuenta que el caso que se pregunta es bastante simple y que los casos más complejos pueden requerir enfoques más complejos. En particular:

    • Si desea modificar la estructura de la SQL basado en la entrada del usuario, consultas con parámetros no va a ayudar, y el escape necesario no está cubierto por mysql_real_escape_string. En este tipo de caso, sería mejor pasar la entrada del usuario a través de una lista blanca para asegurarse de que sólo «segura» de valores.
    • Si utiliza los números enteros a partir de la entrada del usuario en una condición y tomar el mysql_real_escape_string enfoque, usted va a sufrir el problema descrito por Polinomio en los comentarios de abajo. Este caso es más complicado porque enteros no sería rodeado por comillas, por lo que podría tratar mediante la validación de que la entrada del usuario contiene sólo dígitos.
    • Hay otros casos que no soy consciente de. Usted puede encontrar este es un recurso útil en algunos de los problemas más sutiles que usted puede encontrar.
    el uso de mysql_real_escape_string es suficiente o debo utilizar con parámetros demasiado?
    mantener una buena práctica de uso de las consultas parametrizadas, incluso en un proyecto local. Con las consultas parametrizadas que son garantizado de que no habrá de inyección de SQL. Pero tenga en cuenta que usted debe desinfectar los datos para evitar falsos de recuperación (es decir, XSS, inyección, tales como poner el código HTML en un texto) con htmlentities por ejemplo
    Una buena práctica para las consultas parametrizadas y enlazar los valores, pero real, de escapar de la cadena es bueno, por ahora

    OriginalEl autor

  3. 973

    Cada respuesta aquí cubre sólo una parte del problema.
    De hecho, hay cuatro de consulta diferentes partes de las que se puede añadir de forma dinámica: –

    • una cadena
    • un número
    • un identificador
    • una sintaxis de la palabra clave.

    Y sentencias preparadas de la cubierta sólo dos de ellos.

    Pero a veces tenemos que hacer nuestra consulta aún más dinámico, la adición de los operadores o identificadores así.
    Por lo tanto, vamos a necesitar diferentes técnicas de protección.

    En general, un enfoque de la protección se basa en listas blancas.

    En este caso, cada parámetro dinámico debe ser codificado en la secuencia de comandos y elegido de ese conjunto.
    Por ejemplo, para hacer la dinámica de pedido:

    $orders  = array("name", "price", "qty"); //Field names
    $key     = array_search($_GET['sort'], $orders)); //See if we have such a name
    $orderby = $orders[$key]; //If not, first one will be set automatically. smart enuf :)
    $query   = "SELECT * FROM `table` ORDER BY $orderby"; //Value is safe

    Sin embargo, hay otra manera de proteger a los identificadores de – escape. Mientras usted tiene un identificador citado, puede escapar comillas simples inclinadas dentro de la duplicación de ellos.

    Como un paso más, se puede pedir prestado un verdaderamente brillante idea de usar algún marcador de posición (un proxy para representar el valor real en la consulta) a partir de las declaraciones preparadas y inventar un marcador de posición de otro tipo – un identificador de marcador de posición.

    Así que, para hacer el cuento largo corto: es un marcador de posiciónno declaración preparada puede ser considerado como una bala de plata.

    Así, una recomendación general puede ser formulada como
    Mientras usted está agregando partes dinámicas para la consulta de uso de marcadores de posición (y estos marcadores se procesa correctamente, por supuesto), usted puede estar seguro de que su consulta es seguro.

    Aún así, hay un problema con la sintaxis de SQL palabras clave (tales como ANDDESC y tal), pero la lista blanca parece que el único enfoque en este caso.

    Actualización

    Aunque hay un acuerdo general sobre las mejores prácticas con respecto a la inyección de SQL protección, hay todavía muchas malas prácticas. Y algunos de ellos demasiado profundamente arraigada en la mente de los usuarios de PHP. Por ejemplo, en esta misma página hay (aunque invisible para la mayoría de los visitantes) más de 80 eliminado respuestas – quita todo por la comunidad debido a la mala calidad o la promoción de mala, y anticuadas prácticas. Peor aún, algunas de las malas respuestas no son eliminados, sino que prospera.

    Por ejemplo, (1) son(2) todavía(3) muchos(4) respuestas(5)incluyendo la segundo, la mayoría de los upvoted respuesta lo que sugiere que el manual de cadena de escape – un enfoque obsoleto que ha demostrado ser inseguro.

    O hay un poco mejor respuesta que sugiere otro método de cadena de formato e incluso se jacta como la panacea. Aunque, por supuesto, no lo es. Este método no es mejor que regular el formato de cadena, sin embargo, mantiene todos sus inconvenientes: es aplicable a las cadenas sólo y, al igual que cualquier otro formato manual, es esencialmente opcional, no obligatorio, medir, propenso a errores humanos de cualquier tipo.

    Creo que todo esto debido a una muy antigua superstición, apoyado por las autoridades como OWASP o el manual de PHPque proclama la igualdad entre lo que «escapar» y la protección de las inyecciones de SQL.

    Independientemente de lo que el manual de PHP dijo por edades, *_escape_string de ninguna manera hace que la seguridad de los datos y nunca ha sido la intención. Además de ser inútil para cualquier SQL parte de otros de la cadena, manual de escape que está mal, porque es manual como opuesto a automatizadas.

    Y OWASP empeora aún más la situación, haciendo hincapié en escapar de entrada de usuario que es una absoluta tontería: no hay palabras en el contexto de la inyección de protección. Cada variable es potencialmente peligroso – no importa la fuente! O, en otras palabras, cada variable debe tener el formato adecuado para ser puesto en una consulta – no importa la fuente de nuevo. Es el destino lo que importa. El momento en que un desarrollador comienza a separar las ovejas de las cabras (pensando si alguna variable en particular es «seguro» o no) que él/ella toma su primer paso hacia el desastre. Por no hablar de que incluso la redacción sugiere masiva de escape en el punto de entrada, que se asemeja a la muy magic quotes característica – ya despreciado, desaprobados y retirados.

    Así, a diferencia de lo que sea «escapar», declaraciones preparadas es la medida en que, de hecho, protege de la inyección de SQL (cuando sea aplicable).

    Si todavía no estás convencido, aquí hay un paso a paso la explicación que yo escribí, La Guía del Autostopista a la Inyección de SQL prevencióndonde me explicó todo en detalle estas cuestiones e incluso compilado una sección enteramente dedicada a las malas prácticas y su divulgación.

    Grandes, bien pensado artículo. Yo podría añadir que el uso de los Desinfectar los filtros de PHP es una especie de (pero no exactamente) una lista blanca de clase. Por ejemplo, FILTER_SANITIZE_NUMBER_INT sólo permite que el número de caracteres, lo blanco listado de personajes, no de cadenas enteras. En combinación con sentencias preparadas, hace un buen cinturón y tirantes».
    usted no necesita la creación de listas blancas de aquí. Cualquiera de saneamiento será redundante. Menos reglas a seguir, menos errores que usted hará. Si bien se puede hacer cualquier validaciones, hazlo por el bien de la lógica de la aplicación, pero no para la base de datos.

    OriginalEl autor

  4. 786

    Me gustaría recomendar el uso PDO (Objetos de Datos de PHP) para ejecutar consultas SQL con parámetros.

    Esto no sólo protege contra ataques de inyección SQL, también acelera las consultas.

    Y mediante el uso de PDO en lugar de mysql_mysqli_y pgsql_ funciones, su aplicación un poco más abstractas de la base de datos, en el caso poco probable de tener que cambiar la base de datos de proveedores.

    no PDO envoltura de mysqli para MySQL DBs? En cuyo caso seguramente no puede ser más rápida que la de mysqli. Me gustaría recomendar que si. Es mucho mejor la interfaz que el mysqli API.
    El uso de consultas parametrizadas es lo que acelera las consultas. Técnicamente mysqli podría ser incluso más rápido por un margen muy pequeño. La cantidad real de tiempo que el servidor tarda en responder la consulta de los eclipses cualquier diferencia en el tiempo que podría suceder debido a que usted está usando un contenedor. Pero mysqli está vinculada a la base de datos. Si desea utilizar otro motor de base de datos, usted tiene que cambiar todas las llamadas que utilizar mysqli. No así para los PDO.
    PDO no admite la dinámica order by por desgracia 🙁

    OriginalEl autor

  5. 582

    Uso PDO y consultas preparadas.

    ($conn es un PDO objeto)

    $stmt = $conn->prepare("INSERT INTO tbl VALUES(:id, :name)");
    $stmt->bindValue(':id', $id);
    $stmt->bindValue(':name', $name);
    $stmt->execute();
    Desde wikipedia: sentencias Preparadas son resistentes contra inyección SQL, debido a que los valores de parámetros, los cuales son transmitidos posteriormente mediante un protocolo diferente, no tiene que ser correctamente escape. Si la declaración original de la plantilla no se deriva de una entrada externa, la inyección de SQL no puede ocurrir.

    OriginalEl autor

  6. 516

    Como se puede ver, la gente sugieren que el uso de declaraciones preparadas en la mayoría de los. No está mal, pero cuando la consulta se ejecuta sólo una vez por proceso, habría una ligera reducción en el rendimiento.

    Yo estaba frente a este problema, pero creo que lo resuelto en muy sofisticada manera – la manera en que utilizan los hackers para evitar el uso de comillas. He utilizado esto en conjunto con emulado declaraciones preparadas. Yo lo uso para prevenir todos tipos de posibles ataques de inyección de SQL.

    Mi enfoque:

    • Si usted espera de entrada a ser entero asegurarse de que realmente entero. En una variable tipo de lenguaje como PHP es este muy importante. Se puede utilizar por ejemplo esta muy simple pero potente solución: sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);

    • Si esperar nada más de entero hex es. Si usted hex, va perfectamente escapar de todas las entradas. En C/C++ hay una función llamada mysql_hex_string()en PHP se puede utilizar bin2hex().

      No te preocupes que en el escaparon de la cadena tendrá un 2x tamaño de su longitud original, porque incluso si usted usa mysql_real_escape_stringPHP tiene que asignar la misma capacidad ((2*input_length)+1)que es el mismo.

    • Este hex método se utiliza a menudo cuando la transferencia de datos binarios, pero no veo ninguna razón por qué no usarlo en todos los datos para evitar ataques de inyección SQL. Tenga en cuenta que usted tiene que anteponer los datos con 0x o usar el MySQL función UNHEX lugar.

    Así, por ejemplo, la consulta:

    SELECT password FROM users WHERE name = 'root'

    Será:

    SELECT password FROM users WHERE name = 0x726f6f74

    o

    SELECT password FROM users WHERE name = UNHEX('726f6f74')

    Hex es el escape perfecto. No hay manera de inyectar.

    Diferencia entre UNHEX la función y el prefijo 0x

    Hay algo de debate en los comentarios, así que finalmente, quiero dejar claro. Estos dos métodos son muy similares, pero son un poco diferentes en algunos aspectos:

    * * 0** prefijo sólo puede ser utilizado para las columnas de datos, tales como char, varchar, text, bloque, binario, etc.

    También, su uso es un poco complicado si usted va a insertar una cadena vacía. Usted tendrá que sustituir por completo con '', o usted conseguirá un error.

    UNHEX() obras en cualquier columna; usted no tiene que preocuparse acerca de la cadena vacía.


    Hex métodos se utilizan a menudo como ataques

    Tenga en cuenta que este hex método se utiliza a menudo como un ataque de inyección SQL donde enteros son como cadenas y se escapó solo con mysql_real_escape_string. Entonces usted puede evitar el uso de comillas.

    Por ejemplo, si usted acaba de hacer algo como esto:

    "SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])

    un ataque puede inyectar muy fácilmente. Considere el siguiente inyecta código devuelto por el script:

    SELECCIONE … where id = -1 union all select table_name de information_schema.tablas

    y ahora acaba de extraer la estructura de la tabla:

    SELECCIONE … where id = -1 union all select column_name de information_schema.columna donde table_name = 0x61727469636c65

    Y, a continuación, seleccione los datos que querían. ¿No es genial?

    Pero si el codificador de un inyectable sitio del hexagonal, sin inyección sería posible debido a que la consulta tendría este aspecto: SELECT ... WHERE id = UNHEX('2d312075...3635')

    Sí, lo hiciste. MySQL no concatenar con + pero con CONCAT. Y para el rendimiento: yo no creo que afecta el rendimiento debido a que mysql tiene que analizar los datos y no importa si el origen es la cadena o hexadecimal
    ¿Qué errores que encuentra? Ser específico.
    Usted no entiende el concepto… Si usted quiere tener una cadena de caracteres en mysql que usted cita como esta 'root' o puede hex es 0x726f6f74 PERO si quieres un número y enviarlo como cadena probablemente escribir ’42’ no CHAR(42) … ’42’ en hexadecimal sería 0x3432 no 0x42
    Yo no tengo nada que decir… simplemente lol… si todavía quieres tratar hex en campos numéricos, ver el segundo comentario. Apuesto a que me voy a trabajar.
    todavía no entiendo ? Usted puede utilizar 0x y concat porque si la cadena es vacía terminará con un error. Si desea alternativa sencilla para su consulta probar este SELECT title FROM article WHERE id = UNHEX(' . bin2hex($_GET["id"]) . ')

    OriginalEl autor

  7. 468

    IMPORTANTE

    La mejor manera de evitar la Inyección SQL es el uso de Declaraciones Preparadas en lugar de escapar de lacomo el aceptó responder demuestra.

    Hay bibliotecas como Aura.Sql y EasyDB que permiten a los desarrolladores el uso de declaraciones preparadas más fácil. Para aprender más acerca de por qué las declaraciones preparadas son mejores en detener la inyección de SQLconsulte este mysql_real_escape_string() bypass y recientemente fijo Unicode vulnerabilidades de Inyección SQL en WordPress.

    Inyección de prevención – mysql_real_escape_string()

    PHP tiene una especial función realizada para prevenir estos ataques. Todo lo que necesitas hacer es utilizar el bocado de una función, mysql_real_escape_string.

    mysql_real_escape_string toma una cadena que se va a utilizar en una consulta de MySQL y retorno de la misma cadena con todas las de inyección de SQL intentos se escapó. Básicamente, va a reemplazar esos molestos comillas(‘) un usuario puede entrar con una base de datos MySQL-seguro sustituto, el carácter de escape de cotización \’.

    NOTA: debe estar conectado a la base de datos para utilizar esta función!

    //Conectarse a MySQL

    $name_bad = "' OR 1'"; 
    
    $name_bad = mysql_real_escape_string($name_bad);
    
    $query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
    echo "Escaped Bad Injection: <br />" . $query_bad . "<br />";
    
    
    $name_evil = "'; DELETE FROM customers WHERE 1 or username = '"; 
    
    $name_evil = mysql_real_escape_string($name_evil);
    
    $query_evil = "SELECT * FROM customers WHERE username = '$name_evil'";
    echo "Escaped Evil Injection: <br />" . $query_evil;

    Usted puede encontrar más detalles en MySQL – SQL Inyección de Prevención.

    Esta es la mejor que se puede hacer con el legado de la extensión mysql. Para el nuevo código, se le aconseja a cambiar a mysqli o PDO.
    No estoy de acuerdo con esta especialmente hecho a la función para prevenir estos ataques’. Creo que mysql_real_escape_string propósito es el de permitir a construir correcta de consultas SQL para cada entrada de datos de cadena. La prevención de la inyección de sql es el efecto secundario de esta función.
    no utilizar las funciones para escribir la entrada de datos de cadenas de caracteres. Usted acaba de escribir que no necesita escapar o ya se han escapado. mysql_real_escape_string() puede haber sido diseñado con el propósito de mencionar que en la mente, sino que su único valor es la prevención de la inyección.
    ADVERTENCIA! mysql_real_escape_string() no es infalible.
    mysql_real_escape_string ahora es obsoleto, por lo que ya no es una opción viable. Va a ser eliminada en el futuro de PHP. Su mejor manera de avanzar en lo que el PHP o MySQL gente recomendamos.

    OriginalEl autor

  8. 424

    Advertencia de seguridad: Esta respuesta no está en línea con las mejores prácticas de seguridad. Escapar es insuficiente para evitar la inyección de código SQLuso declaraciones preparadas lugar. Use la estrategia que se describen a continuación bajo su propio riesgo. (También, mysql_real_escape_string() fue eliminado en PHP 7.)

    Usted podría hacer algo básico como esto:

    $safe_variable = mysql_real_escape_string($_POST["user-input"]);
    mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

    Esto no solucionará todos los problemas, pero es un muy buen paso. He dejado fuera obvio elementos tales como el control de la variable de la existencia, el formato (números, letras, etc.).

    He probado tu ejemplo y es un trabajo muy bien para mí.Podría borrar «esto no va a resolver todos los problemas»
    Si usted no cita la cadena, todavía inyectable. Tomar $q = "SELECT col FROM tbl WHERE x = $safe_var"; por ejemplo. Configuración de $safe_var a 1 UNION SELECT password FROM users funciona en este caso, debido a la falta de cotizaciones. También es posible inyectar cadenas en la consulta mediante CONCAT y CHR.
    Toda la razón, pero me gustaría ver que esto sólo como uso incorrecto. Como usted lo usa correctamente, definitivamente el trabajo.
    ADVERTENCIA! mysql_real_escape_string() no es infalible.
    mysql_real_escape_string ahora es obsoleto, por lo que ya no es una opción viable. Va a ser eliminada en el futuro de PHP. Su mejor manera de avanzar en lo que el PHP o MySQL gente recomendamos.

    OriginalEl autor

  9. 357

    Lo que termina de usar, asegúrese de que usted revise su entrada no ha sido destrozado por magic_quotes o algún otro significado bien la basura, y si es necesario, ejecute a través de stripslashes o lo que sea para desinfectarlo.

    De hecho, corriendo con magic_quotes encendido sólo alienta a los pobres de la práctica. Sin embargo, a veces usted no siempre puede controlar el entorno a ese nivel – usted no tiene acceso para administrar el servidor, o que su aplicación tiene que coexistir con las aplicaciones que (estremecimiento) dependen de la configuración. Por estas razones, es bueno escribir aplicaciones portátiles – aunque, obviamente, el esfuerzo es en vano si no controlar el entorno de implementación, por ejemplo, porque es una en la casa de la aplicación, o sólo va a ser utilizado en su entorno específico.
    A partir de PHP 5.4, la abominación conocido como «magic quotes» ha sido muertos muertos. Y enhorabuena a los malos de la basura.

    OriginalEl autor

  10. 341

    Con parámetros de consulta Y validación de la entrada es el camino a seguir. Hay muchos escenarios en los que la inyección de SQL pueden producirse, aunque mysql_real_escape_string() ha sido utilizado.

    Esos ejemplos son vulnerables a la inyección de SQL:

    $offset = isset($_GET['o']) ? $_GET['o'] : 0;
    $offset = mysql_real_escape_string($offset);
    RunQuery("SELECT userid, username FROM sql_injection_test LIMIT $offset, 10");

    o

    $order = isset($_GET['o']) ? $_GET['o'] : 'userid';
    $order = mysql_real_escape_string($order);
    RunQuery("SELECT userid, username FROM sql_injection_test ORDER BY `$order`");

    En ambos casos, no se puede usar ' para proteger la encapsulación.

    Fuente: El Inesperado Inyección de SQL (Al Escapar No Es Suficiente)

    Usted puede evitar la inyección SQL si adoptar una entrada de validación de la técnica en la que la entrada del usuario se autentica en un conjunto de reglas definidas para la longitud, el tipo y la sintaxis y también en contra de las reglas de negocio.

    OriginalEl autor

  11. 291

    En mi opinión, la mejor manera para evitar la inyección de SQL en una aplicación de PHP (o cualquier aplicación web, para el caso) es para pensar acerca de su aplicación a la arquitectura. Si la única manera de protegerse contra la inyección de SQL es recordar a la utilización de un método o función que hace lo Correcto cada vez que hable a la base de datos, lo están haciendo mal. De esa manera, es sólo una cuestión de tiempo hasta que se te olvida correctamente el formato de la consulta en algún momento de su código.

    Adoptar el patrón MVC y un framework como CakePHP o CodeIgniter es probablemente el camino a seguir: tareas Comunes como la creación de base de datos segura consultas se han resuelto de forma centralizada implementado en dichos marcos. Ellos te ayudan a organizar tu aplicación web de una manera sensible y te hacen pensar más en cargar y guardar los objetos que acerca de forma segura a la construcción única de consultas SQL.

    Yo creo que tu primer párrafo es importante. La comprensión es la clave. Además, todo el mundo no es trabajar para una empresa. Para una gran franja de la gente, los marcos de realidad van en contra de la idea de . Teniendo intimidad con los fundamentos no pueden ser valorados trabajando en una fecha límite, pero el do-it-yourselfers allí disfrutar de ensuciarse las manos. Marco desarrolladores no son tan privilegiados que todo el mundo debe inclinarse y se supone que nunca cometen errores. El poder para tomar decisiones es todavía importante. Quién es para decir que mi marco no desplazar a algún otro esquema en el futuro?
    Usted está absolutamente en lo correcto. Es muy importante para entiendo lo que está pasando y por qué. Sin embargo, la probabilidad de que un cierto-y-probado y usado activamente y marco desarrollado se ha ejecutado y resolver un montón de problemas y parcheado un montón de agujeros de seguridad ya es bastante alto. Es una buena idea mirar en la fuente para tener una idea de la calidad del código. Si es un probados lío probablemente no seguro.
    Aquí. Aquí. Buenos puntos. Sin embargo, ¿estaría usted de acuerdo en que muchas personas pueden estudiar y aprender a adoptar una MVC sistema, pero no todo el mundo puede reproducir a mano (controladores y servidor). Uno puede ir demasiado lejos con este punto. ¿Debo entender que mi microondas antes de calentar mi mantequilla de maní pecan las cookies de mi amiga me hizo? 😉
    Estoy de acuerdo! Creo que el caso de uso que hace una diferencia demasiado: Estoy construyendo una galería de fotos de mi página personal o soy la construcción de una banca en línea de la aplicación web? En el último caso es muy importante para entender los detalles de la seguridad y de cómo un marco en el que yo estoy usando es abordar aquellos.
    Ah, la excepción de seguridad para el do it yourself corolario. A ver, yo tiendo a estar dispuesto a correr el riesgo e ir a por todas. 🙂 Es broma. Con tiempo suficiente, la gente puede aprender a hacer una bastante seguro de aplicaciones. Demasiadas personas están en un apuro. Ellos lanzan sus manos arriba y se supone que los marcos son seguros. Después de todo, ellos no tienen el tiempo suficiente para probar y entender las cosas. Por otra parte, la seguridad es un campo que requiere estudio dedicado. No es algo simple de los programadores de conocer en profundidad por la virtud de la comprensión de los algoritmos y patrones de diseño.

    OriginalEl autor

  12. 275

    Estoy a favor de los procedimientos almacenados (MySQL ha tenido procedimientos almacenados desde 5.0) desde un punto de vista de seguridad – las ventajas son –

    1. La mayoría de las bases de datos (incluyendo MySQL) permitir el acceso del usuario a ser restringido a la ejecución de procedimientos almacenados. El grano fino de seguridad de control de acceso es útil para prevenir la escalada de privilegios de los ataques. Esto impide que se vea comprometida aplicaciones de ser capaz de ejecutar SQL directamente contra la base de datos.
    2. Que resumen el raw de la consulta SQL de la aplicación, por lo menos información de la estructura de base de datos está disponible para la aplicación. Esto hace que sea más difícil para la gente entender la estructura subyacente de la base de datos y el diseño adecuado de los ataques.
    3. Sólo aceptan parámetros, de modo que las ventajas de consultas con parámetros están ahí. De curso de la OMI usted todavía necesita para limpiar su entrada – especialmente si usted está utilizando SQL dinámico dentro del procedimiento almacenado.

    Las desventajas son –

    1. Ellos (procedimientos almacenados) son difíciles de mantener y tienden a multiplicarse muy rápidamente. Esto hace que la gestión de ellos un problema.
    2. No son muy adecuados para la dinámica de las consultas – si ellos están diseñados para aceptar el código dinámico como parámetros, a continuación, muchas de las ventajas son negados.

    OriginalEl autor

  13. 271

    Hay muchas maneras de prevenir inyecciones SQL y otras SQL hacks. Usted puede encontrar fácilmente en Internet (Búsqueda de Google). Por supuesto DOP es una de las buenas soluciones. Pero me gustaría sugerir algunos buenos enlaces de prevención de la Inyección de SQL.

    ¿Qué es la inyección de SQL y cómo prevenir

    El manual de PHP para la inyección de SQL

    Microsoft explicación de la inyección de SQL y la prevención en PHP

    y algunos otros como La prevención de la inyección de SQL con MySQL y PHP

    Ahora, ¿por qué usted necesita para prevenir la consulta de la inyección de SQL?

    Me gustaría conocer: ¿por Qué tratamos de prevenir la inyección de SQL con un breve ejemplo a continuación:

    De consulta para la autenticación de inicio de sesión partido:

    $query="select * from users where email='".$_POST['email']."' and password='".$_POST['password']."' ";

    Ahora, si alguien (un hacker) pone

    $_POST['email']= [email protected].com' OR '1=1

    y la contraseña de cualquier cosa….

    La consulta será analizado en el sistema sólo hasta:

    $query="select * from users where email='[email protected]' OR '1=1';

    La otra parte, serán desechados. Entonces, ¿qué ocurrirá? Un usuario no autorizado (hacker) será capaz de iniciar sesión como administrador, sin tener su contraseña. Ahora, él puede hacer cualquier cosa que admin/correo electrónico persona puede hacer. A ver, es muy peligroso si la inyección de SQL no es prevenido.

    OriginalEl autor

  14. 249

    Creo que si alguien quiere usar PHP y MySQL o algún otro servidor de base de datos:

    1. Piensa acerca del aprendizaje PDO (Objetos de Datos de PHP) – es una base de datos de la capa de acceso proporciona un método uniforme de acceso a varias bases de datos.
    2. Piensa acerca del aprendizaje MySQLi
    3. El uso de funciones de PHP como: strip_tagsmysql_real_escape_string o si la variable numérica, sólo (int)$foo. Leer más sobre el tipo de las variables en PHP aquí. Si usted está usando las bibliotecas, tales como PDO o MySQLi, siempre uso PDO::cotización() y mysqli_real_escape_string().

    Bibliotecas ejemplos:

    —- PDO

    —– No hay marcadores de posición – maduro para la inyección de SQL! Es malo

    $request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)");

    —– Sin nombre marcadores de posición

    $request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?);

    —– Marcadores de posición con nombre

    $request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)");

    MySQLi

    $request = $mysqliConnection->prepare('
           SELECT * FROM trainers
           WHERE name = ?
           AND email = ?
           AND last_login > ?');
    
        $query->bind_param('first_param', 'second_param', $mail, time() - 3600);
        $query->execute();

    P. S:

    PDO es el ganador de esta batalla con facilidad. Con el apoyo de doce
    diferentes controladores de base de datos y el nombre de los parámetros, podemos ignorar la
    pequeña pérdida de rendimiento, y acostumbrarse a su API. De seguridad
    punto de vista, tanto de ellos son seguros siempre y cuando el desarrollador utiliza
    la forma en que se supone para ser utilizado

    Pero mientras tanto PDO y MySQLi es bastante rápido, MySQLi realiza
    insignificantemente más rápido en los puntos de referencia – ~2.5% para los no preparados
    declaraciones, y ~6,5% para los preparados.

    Y por favor, pruebe cada consulta a la base de datos – es una mejor manera de prevenir la inyección.

    OriginalEl autor

  15. 237

    Si es posible, de fundición de los tipos de sus parámetros. Pero es sólo trabajando en los tipos simples como int, bool, y flotar.

    $unsafe_variable = $_POST['user_id'];
    
    $safe_variable = (int)$unsafe_variable ;
    
    mysqli_query($conn, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
    Este es uno de los pocos casos en los que me gustaría utilizar un «escapó de valor» en lugar de una declaración preparada. Y de tipo entero conversión es extremadamente eficiente.

    OriginalEl autor

  16. 219

    Si usted desea tomar ventaja de caché de motores, como Redis o Memcachedtal vez DALMP podría ser una opción. Se utiliza puro MySQLi. Marque esta: DALMP Capa de Abstracción de Base de datos para MySQL usando PHP.

    También, se puede «preparar» tus argumentos antes de la preparación de la consulta, por lo que usted puede crear consultas dinámicas y al final tienen un totalmente preparado declaraciones de consulta. DALMP Capa de Abstracción de Base de datos para MySQL usando PHP.

    OriginalEl autor

  17. 211

    El uso de esta función de PHP mysql_escape_string() usted puede conseguir una buena prevención de una forma rápida.

    Por ejemplo:

    SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."'

    mysql_escape_string — Escapa una cadena para su uso en un mysql_query

    Para más prevención, usted puede añadir al final …

    wHERE 1=1   or  LIMIT 1

    Finalmente se obtiene:

    SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1

    OriginalEl autor

  18. 211

    Para aquellos seguro de cómo usar PDO (procedente de la mysql_ funciones), hice un muy, muy simple contenedor de PDO que es un solo archivo. Existe para mostrar lo fácil que es hacer todas las cosas en común de las aplicaciones se deben realizar. Funciona con PostgreSQL, MySQL y SQLite.

    Básicamente, leer mientras usted lee el manual a ver cómo poner el PDO funciones para utilizar en la vida real para hacer que sea sencillo para almacenar y recuperar los valores en el formato que desea.

    Quiero una sola columna

    $count = DB::column('SELECT COUNT(*) FROM `user`);

    Quiero una matriz(clave = = > valor) resultados (es decir, para hacer una selectbox)

    $pairs = DB::pairs('SELECT `id`, `username` FROM `user`);

    Quiero una sola fila de resultado

    $user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id));

    Quiero una matriz de resultados

    $banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE));

    OriginalEl autor

  19. 192

    Unas pautas para escapar caracteres especiales en las sentencias SQL.

    No uso MySQLesta extensión está en desuso, uso MySQLi o PDO.

    MySQLi

    Manualmente para escapar caracteres especiales en una cadena, se puede utilizar el mysqli_real_escape_string función. La función no funcionará correctamente a menos que el conjunto de caracteres correcto es establecer con mysqli_set_charset.

    Ejemplo:

    $mysqli = new mysqli( 'host', 'user', 'password', 'database' );
    $mysqli->set_charset( 'charset');
    
    $string = $mysqli->real_escape_string( $string );
    $mysqli->query( "INSERT INTO table (column) VALUES ('$string')" );

    De escape automático de valores con sentencias preparadas, uso mysqli_preparey mysqli_stmt_bind_param donde los tipos para el correspondiente enlace variables debe ser proporcionado para una adecuada conversión:

    Ejemplo:

    $stmt = $mysqli->prepare( "INSERT INTO table ( column1, column2 ) VALUES (?,?)" );
    
    $stmt->bind_param( "is", $integer, $string );
    
    $stmt->execute();

    No importa si usted utiliza declaraciones preparadas o mysqli_real_escape_string, siempre tienes que saber el tipo de datos de entrada que estás trabajando.

    Así que si usted utiliza una instrucción preparada, debe especificar los tipos de las variables para la mysqli_stmt_bind_param función.

    Y el uso de mysqli_real_escape_string es para, como su nombre lo dice, escapar caracteres especiales en una cadena, por lo que no hará enteros seguro. El propósito de esta función es evitar la ruptura de las cadenas en las sentencias SQL, y el daño a la base de datos que pueda causar. mysqli_real_escape_string es una función útil cuando se utiliza correctamente, especialmente cuando se combina con sprintf.

    Ejemplo:

    $string = "x' OR name LIKE '%John%";
    $integer = '5 OR id != 0';
    
    $query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );
    
    echo $query;
    //SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 5
    
    $integer = '99999999999999999999';
    $query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );
    
    echo $query;
    //SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 2147483647
    La pregunta es muy genérica. Algunos grandes respuestas anteriores, pero la mayoría sugieren declaraciones preparadas. MySQLi async no admite declaraciones preparadas, por lo que el sprintf parece una gran opción para esta situación.

    OriginalEl autor

  20. 171

    La alternativa simple a este problema podría ser resuelto mediante la concesión de permisos adecuados en la base de datos.
    Por ejemplo: si usted está utilizando una base de datos MySQL, a continuación, entrar en la base de datos a través de la terminal o de la interfaz de usuario proporcionada y sólo tienes que seguir este orden:

     GRANT SELECT, INSERT, DELETE ON database TO [email protected]'localhost' IDENTIFIED BY 'password';

    Se limita el usuario para obtener sólo limita con la consulta especificada sólo. Quitar el permiso de eliminación y por lo que los datos nunca se borran de la consulta disparado desde la página PHP.
    La segunda cosa a hacer es enjuagar los privilegios, de modo que el MySQL actualiza los permisos y actualizaciones.

    FLUSH PRIVILEGES; 

    obtener más información acerca de rubor.

    Para ver la corriente de privilegios para el usuario de bomberos la siguiente consulta.

    select * from mysql.user where User='username';

    Aprender más acerca de CONCEDER.

    Esta respuesta es esencialmente malya que no ayuda a prevenir una inyección de prevención, sino simplemente tratando de suavizar las consecuencias. En vano.
    A la derecha, no ofrece una solución, pero es lo que puede hacer antes de la mano para evitar que cosas.
    Si mi meta es leer la información privada de su base de datos, luego de no tener el permiso de eliminación no significa nada.
    Tomarlo con calma, yo era sólo lo que sugiere buenas prácticas para suavizar las consecuencias.
    Usted no quiere para «suavizar las consecuencias», usted quiere hacer todo lo posible para proteger en contra de ella. Para ser justo, a pesar de que, al establecer el correcto acceso de usuario es importante, pero no es realmente lo que el OP está pidiendo.

    OriginalEl autor

  21. 167

    Yo uso tres maneras diferentes para prevenir que mi aplicación web de ser vulnerable a inyección SQL.

    1. Uso de mysql_real_escape_string()que es un pre-función definida en PHPy este código de agregar barras diagonales inversas a los siguientes personajes: \x00\n\r\'" y \x1a. Pasar los valores de entrada como parámetros para minimizar la posibilidad de inyección de SQL.
    2. La más avanzada es la utilización de PDOs.

    Espero que esto te ayude.

    Considere la siguiente consulta:

    $iId = mysql_real_escape_string("1 OR 1=1");
    $sSql = "SELECT * FROM table WHERE id = $iId";

    mysql_real_escape_string() no va a proteger. Si el uso de comillas simples (‘ ‘) alrededor de sus variables dentro de la consulta es lo que te protege en contra de esto. Aquí es una solución que aparece a continuación para esto:

    $iId = (int) mysql_real_escape_string("1 OR 1=1");
    $sSql = "SELECT * FROM table WHERE id = $iId";

    Este pregunta tiene algunas buenas respuestas acerca de este.

    Sugiero, utilizando PDO es la mejor opción.

    Edición:

    mysql_real_escape_string() es obsoleta a partir de PHP 5.5.0. Utilizar mysqli o PDO.

    Una alternativa a mysql_real_escape_string() es

    string mysqli_real_escape_string ( mysqli $link , string $escapestr )

    Ejemplo:

    $iId = $mysqli->real_escape_string("1 OR 1=1");
    $mysqli->query("SELECT * FROM table WHERE id = $iId");

    OriginalEl autor

  22. 161

    Una forma sencilla sería usar un PHP framework como CodeIgniter o Laravel que han incorporado características como el filtrado y activo-registro, para que usted no tiene que preocuparse acerca de estos matices.

    Creo que todo el punto de la cuestión es hacer esto sin el uso de dicho marco.

    OriginalEl autor

  23. 159

    Con respecto a muchas de las respuestas útiles, espero que añadir que algunos de los valores de este hilo.
    La inyección SQL es un ataque que se puede hacer a través de entradas (Insumos que llena por el usuario y, a continuación, se utiliza dentro de las consultas), La inyección de SQL patrones de corregir la sintaxis de la consulta, mientras que podemos llamar: mala consultas por malas razones, suponemos que no puede ser una mala persona que trate de obtener información secreta (omisión de control de acceso) que afecta a los tres principios de la seguridad (Confidencialidad, Integridad, Disponibilidad).

    Ahora, nuestro punto es para prevenir amenazas a la seguridad, tales como ataques de inyección de SQL, la pregunta (¿Cómo prevenir el ataque de inyección de SQL con PHP), ser más realista, el filtrado de datos o borrado de los datos de entrada es el caso cuando se utiliza el usuario de entrada de datos en el interior de dicha consulta, usando PHP o cualquier otro lenguaje de programación, no es el caso, o según lo recomendado por más personas a utilizar la tecnología moderna, tales como la declaración preparada o cualquier otra herramienta que en la actualidad soporta la inyección de SQL prevención, considere la posibilidad de que estas herramientas no disponibles más? La forma de proteger su aplicación?

    Mi enfoque en contra de la inyección de SQL es: la limpieza de la entrada de usuario los datos antes de enviarlos a la base de datos (antes de usarla en el interior de la consulta).

    De filtrado de datos (Conversión inseguro de datos seguro de los datos)
    Considere la posibilidad de que PDO y MySQLi no disponible, ¿cómo se puede asegurar su aplicación? No se fuerza el uso de ellos? ¿Qué otros idiomas aparte del PHP? Yo prefiero a proporcionar ideas generales como puede ser usado para un amplio frontera no sólo para el idioma específico.

    1. De usuario de SQL (limitación de privilegios de usuario): es más común en operaciones SQL son (SELECT, UPDATE, INSERT), entonces, ¿por qué dar la ACTUALIZACIÓN de privilegio a un usuario que no lo requieren? Por ejemplo de inicio de sesión, y las páginas de búsqueda son sólo el uso de SELECT, entonces, ¿por qué el uso de DB de usuarios en estas páginas con privilegios elevados?
      REGLA: no crear un usuario de base de datos para todos los privilegios, para todas las operaciones SQL, usted puede crear su esquema (deluser, selectuser, updateuser) como nombres de usuario de fácil uso.

    ver Principio de mínimo privilegio

    1. De filtrado de datos: antes de construir cualquier usuario de la consulta de entrada debe ser validado y se filtra, para los programadores, es importante definir algunas propiedades de cada usuario-variables de entrada:
      tipo de datos, modelo de datos, y la longitud de los datos. un campo que es un número entre (x y y) debe ser exactamente validado utilizando una regla exacta, para un campo que es una cadena de caracteres (texto): el patrón es el caso, por ejemplo, el nombre de usuario debe contener sólo algunos personajes digamos, por ejemplo, [a-zA-Z0-9_-.] la longitud varía entre (x, y n), donde x y n (enteros, x <=n ).
      Regla: la creación exacto filtros y reglas de validación son las mejores prácticas para mí.

    2. Utilizar otras herramientas: Aquí, yo también estarán de acuerdo con usted de que la declaración preparada (parametrizar la consulta) y los procedimientos Almacenados, las desventajas de aquí es que estas formas requiere de habilidades avanzadas que no existen para la mayoría de los usuarios, la idea básica aquí es distinguir entre la consulta SQL y los datos que se utilizan en el interior, ambos enfoques pueden ser utilizados incluso inseguras de datos, debido a que el usuario de los datos de entrada aquí no añade nada a la consulta original, tales como (cualquier o x=x).
      Para obtener más información, por favor lea OWASP Inyección de SQL Prevención de la Hoja de Trucos.

    Ahora, si usted es un usuario avanzado, empezar a usar esta defensa, como quieras, pero, para los principiantes, si no pueden implementar rápidamente procedimiento almacenado y se preparó la declaración, es mejor filtro de entrada de datos en la mayor medida posible.

    Por último, vamos a considerar la posibilidad de que el usuario envía este texto de abajo en lugar de introducir su nombre de usuario:

    [1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'

    Esta entrada puede ser comprobado antes de tiempo sin ninguna instrucción preparada y procedimientos almacenados, pero para estar en el lado seguro, con ellos se inicia después de que el usuario-filtrado de datos y validación.

    El último punto es la detección de un comportamiento inesperado que requiere más esfuerzo y la complejidad; no se recomienda para el normal de las aplicaciones web.
    Un comportamiento inesperado en la anterior entrada del usuario es SELECCIONAR, de la UNIÓN, SI, SUBSTRING, punto de REFERENCIA, SHA, de la raíz una vez que estas palabras se detecta, puede evitar la entrada.

    UPDATE1:

    Un usuario comentó que este post es inútil, OK! Aquí es lo que OWASP.ORG siempre:

    Principales defensas:

    Opción #1: Uso de Sentencias Preparadas (Consultas Parametrizadas)

    Opción #2: Uso de Procedimientos Almacenados

    Opción #3: Escapando de todos Suministrado por el Usuario de Entrada

    Las defensas adicionales:

    También Aplicar: Menos De Privilegio

    También Realizar: Lista Blanca De Validación De Entrada

    Como usted puede saber, afirmando que un artículo debe ser apoyada por el argumento válido, al menos una referencia! De lo contrario, se considera como un ataque y malos dicen!

    Update2:

    Del manual de PHP, PHP: preparación de Declaraciones – Manual:

    Escape y la inyección de SQL

    Las variables vinculadas ser escapado automáticamente por el servidor. El
    inserta sus valores escapados en los lugares adecuados en el
    declaración de la plantilla antes de la ejecución. Una sugerencia debe ser proporcionada a la
    servidor para el tipo de variable ligada, para crear un adecuado
    de conversión. Ver la función mysqli_stmt_bind_param() para obtener más
    información.

    El escape automático de valores en el servidor a veces
    se considera una característica de seguridad para evitar la inyección de código SQL. El mismo
    el grado de seguridad se puede lograr con las sentencias no preparadas si
    los valores de entrada se escapó correctamente.

    Update3:

    He creado los casos de prueba para saber cómo PDO y MySQLi enviar la consulta a MySQL, el servidor cuando se utiliza declaración preparada:

    PDO:

    $user = "''1''"; //Malicious keyword
    $sql = 'SELECT * FROM awa_user WHERE userame =:username';
    $sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
    $sth->execute(array(':username' => $user));

    Registro De Consulta:

        189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
        189 Quit

    MySQLi:

    $stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
    $stmt->bind_param("s", $user);
    $user = "''1''";
    $stmt->execute();

    Registro De Consulta:

        188 Prepare   SELECT * FROM awa_user WHERE username =?
        188 Execute   SELECT * FROM awa_user WHERE username ='\'\'1\'\''
        188 Quit

    Es claro que una declaración preparada también es escapar de los datos, nada más.

    Como también se menciona en la declaración anterior The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctlypor lo tanto, esto demuestra que la validación de datos, tales como intval() es una buena idea para valores enteros antes de enviar cualquier consulta, además, la prevención de usuario malintencionado de datos antes de enviar la consulta es correcta y válida enfoque.

    Por favor, consulte esta pregunta para obtener más detalles: PDO envía raw consulta a MySQL mientras Mysqli envía consulta preparada, ambos producen el mismo resultado

    Referencias:

    1. La Inyección de SQL Hoja de Trucos
    2. La Inyección de SQL
    3. La seguridad de la información
    4. Principios De Seguridad De La
    5. La validación de datos

    OriginalEl autor

  24. 134

    ** Advertencia: el enfoque que se describe en esta respuesta sólo se aplica a muy escenarios específicos y no es seguro debido a los ataques de inyección SQL no sólo depende de ser capaz de inyectar X=Y.**

    Si los atacantes están tratando de hackear el formulario a través de PHP, $_GET variable o con la URL de la cadena de consulta, usted sería capaz de coger ellos si no está seguro.

    RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+)
    RewriteRule ^(.*) ^/track.php

    Porque 1=12=21=22=11+1=2etc… son las preguntas comunes a una base de datos SQL de un atacante. Tal vez también es utilizado por muchos de hacking de aplicaciones.

    Pero hay que tener cuidado, que no se debe reescribir un seguro de la consulta de su sitio. El código anterior es dar un consejo, para volver a escribir o redirigir (depende de ti) que la piratería específicos de la dinámica de la cadena de consulta en una página en la que se almacenará el atacante del Dirección IPo INCLUSO SUS COOKIES, historial del navegador, o cualquier otra información sensible, así que usted puede tratar con ellos más tarde por la prohibición de su cuenta o poniéndose en contacto con las autoridades.

    OriginalEl autor

  25. 125

    Hay tantas respuestas para PHP y MySQLpero aquí está el código para PHP y Oracle para la prevención de la inyección de SQL, así como regular el uso de oci8 conductores:

    $conn = oci_connect($username, $password, $connection_string);
    $stmt = oci_parse($conn, 'UPDATE table SET field = :xx WHERE ID = 123');
    oci_bind_by_name($stmt, ':xx', $fieldval);
    oci_execute($stmt);

    OriginalEl autor

  26. 119

    Una buena idea es utilizar un ‘object-relational mapper como Idiorm:

    $user = ORM::for_table('user')
    ->where_equal('username', 'j4mie')
    ->find_one();
    
    $user->first_name = 'Jamie';
    $user->save();
    
    $tweets = ORM::for_table('tweet')
        ->select('tweet.*')
        ->join('user', array(
            'user.id', '=', 'tweet.user_id'
        ))
        ->where_equal('user.username', 'j4mie')
        ->find_many();
    
    foreach ($tweets as $tweet) {
        echo $tweet->text;
    }

    No sólo le salva de las inyecciones de SQL, pero de los errores de sintaxis también! También Soporta colecciones de modelos con el método de encadenamiento de filtro o aplicar acciones a varios resultados a la vez y múltiples conexiones.

    OriginalEl autor

  27. 116

    Utilizando PDO y MYSQLi es una buena práctica para evitar inyecciones SQL, pero si realmente quieres trabajar con funciones de MySQL y consultas, sería mejor utilizar

    mysql_real_escape_string

    $unsafe_variable = mysql_real_escape_string($_POST['user_input']);

    Hay más habilidades para prevenir esto: como identificar – si la entrada es una cadena, un número, char o matriz, hay tantas incorporado funciones para detectar esto. También, sería mejor utilizar estas funciones para comprobar los datos de entrada.

    is_string

    $unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');

    is_numeric

    $unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');

    Y es mucho mejor usar esas funciones de verificación de datos de entrada con mysql_real_escape_string.

    También, no hay absolutamente ningún punto en la comprobación de $_POST los miembros de la matriz con is_string()
    ADVERTENCIA! mysql_real_escape_string() no es infalible.
    mysql_real_escape_string ahora es obsoleto, por lo que ya no es una opción viable. Será eliminado de PHP en el futuro. Su mejor manera de avanzar en lo que el PHP o MySQL gente recomendamos.
    Tema: no la confianza del usuario de los datos presentados. Cualquier cosa se puede esperar una basura de datos con caracteres especiales o la lógica booleana, que debe convertirse en una parte de la consulta SQL que se pueden ejecutar. Mantener $_POST valores como solo datos, no de SQL parte.

    OriginalEl autor

  28. 82

    He escrito esta pequeña función hace varios años:

    function sqlvprintf($query, $args)
    {
        global $DB_LINK;
        $ctr = 0;
        ensureConnection(); //Connect to database if not connected already.
        $values = array();
        foreach ($args as $value)
        {
            if (is_string($value))
            {
                $value = "'" . mysqli_real_escape_string($DB_LINK, $value) . "'";
            }
            else if (is_null($value))
            {
                $value = 'NULL';
            }
            else if (!is_int($value) && !is_float($value))
            {
                die('Only numeric, string, array and NULL arguments allowed in a query. Argument '.($ctr+1).' is not a basic type, it\'s type is '. gettype($value). '.');
            }
            $values[] = $value;
            $ctr++;
        }
        $query = preg_replace_callback(
            '/{(\d+)}/', 
            function($match) use ($values)
            {
                if (isset($values[$match[1]]))
                {
                    return $values[$match[1]];
                }
                else
                {
                    return $match[0];
                }
            },
            $query
        );
        return $query;
    }
    
    function runEscapedQuery($preparedQuery /*, ...*/)
    {
        $params = array_slice(func_get_args(), 1);
        $results = runQuery(sqlvprintf($preparedQuery, $params)); //Run query and fetch results.   
        return $results;
    }

    Esto permite la ejecución de instrucciones en una sola línea C#-ish Cadena.Formato:

    runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2);

    Se escapa teniendo en cuenta el tipo de variable. Si intenta configurar la tabla, los nombres de columna, fracasaría como se pone cada cadena entre comillas que es una sintaxis no válida.

    ACTUALIZACIÓN de SEGURIDAD: El anterior str_replace versión permite inyecciones agregando {#} tokens en los datos de usuario. Este preg_replace_callback versión no causa problemas si el reemplazo contiene a estos símbolos.

    OriginalEl autor

Dejar respuesta

Please enter your comment!
Please enter your name here