Wednesday 31 August 2016

¿Cómo puedo prevenir la inyección SQL en PHP?

Use declaraciones preparadas y consultas con parámetros. Estas son las sentencias SQL que se envían y procesan mediante el servidor de base de datos de forma independiente de los parámetros. De esta manera es imposible que un atacante inyectar SQL malicioso.

Es, básicamente, tiene dos opciones para lograr esto:

1.El uso de DOP (para cualquier piloto de base de datos compatible):

$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');

$stmt->execute(array('name' => $name));

foreach ($stmt as $row) {
    // do something here with $row
}
2.El uso de MySQLi (para MySQL):

$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name);

$stmt->execute();

$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
    // do something with $row
}
Si se conecta a una base de datos que MySQL, hay una segunda opción específica del controlador que puede hacer referencia a (por ejemplo pg_prepare () y pg_execute () para PostgreSQL). PDO es la opción universal.

Correctamente la configuración de la conexión

Tenga en cuenta que cuando se utiliza PDO para acceder a una base de datos MySQL declaraciones preparadas real no se utilizan de forma predeterminada. Para solucionar este problema, tiene que desactivar la emulación de declaraciones preparadas. Un ejemplo de cómo crear una conexión mediante 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 para añadirlo. De esta manera la secuencia de comandos no se detendrá con un error grave cuando algo va mal. Y se le da al desarrollador la oportunidad de capturar cualquier error (s) que se lanza como PDOExceptions.

Lo que es obligatoria, sin embargo es la primera línea setAttribute (), que dice DOP desactivar comandos preparados emulados y el uso de declaraciones de bienes preparadas. Esto hace que la declaración y los valores no son analizadas por PHP antes de enviarlo al servidor MySQL (dando un posible atacante ninguna posibilidad de inyectar SQL malicioso).

Aunque puede establecer el juego de caracteres en las opciones del constructor, es importante tener en cuenta que las versiones "mayores" de PHP (<5.3.6) ignorado sin el parámetro charset en el DSN.

Explicación

Lo que pasa es que la instrucción SQL que se pasa a preparar es analizada y recopilada por el servidor de base de datos. Al especificar parámetros (ya sea una o un parámetro denominado como:? Nombre en el ejemplo anterior) le dice al motor de base de datos en la que desea filtrar. A continuación, cuando se llama a ejecutar, la declaración preparada se combina con los valores de los parámetros especificados.

Lo importante aquí es que los valores de los parámetros se combinan con la sentencia compilada, no una cadena SQL. la inyección de SQL funciona engañando al script en incluyendo cadenas maliciosas cuando se crea SQL para enviar a la base de datos. Así enviando el SQL real por separado de los parámetros, se limita el riesgo de acabar con algo que no tiene la intención. Cualquier parámetro que envíe al utilizar una declaración preparada se acaba de ser tratados como cadenas (aunque el motor de base de datos puede hacer un poco de optimización de modo parámetros pueden acabar como números también, por supuesto). En el ejemplo anterior, si la variable $ nombre contiene 'Sarah'; CANCELACIÓN de los empleados el resultado sería simplemente una búsqueda de la cadena " 'Sarah'; CANCELACIÓN de los empleados", y no se va a terminar con una mesa vacía.

Otro de los beneficios con el uso de sentencias preparadas es que si se ejecuta la misma instrucción muchas veces en la misma sesión que sólo se analiza y se compila una vez, le da algunos aumentos de velocidad.


Ah, y ya que preguntas acerca de cómo hacerlo para una inserción, he aquí un ejemplo (usando DOP):

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

$preparedStatement->execute(array('column' => $unsafeValue));
Sentencias preparadas pueden ser utilizado para consultas dinámicas?

Si bien todavía se puede utilizar declaraciones preparadas para los parámetros de consulta, la estructura de la consulta dinámica en sí no se puede parametrizar y ciertas características de consultas no puede ser parametrizado.


Para estos escenarios específicos, lo mejor que puede hacer es utilizar un filtro de lista blanca que restringe los valores posibles.

// Value whitelist
  // $dir can only be 'DESC' or 'ASC'
$dir = !empty($direction) ? 'DESC' : 'ASC';