Como prevenir inyecciones SQL en php

Estado
No está abierto para más respuestas.
Mensajes
1
Puntuación de reacción
0
Hola hoy les quiero compartir una manera de evitar inyecciones SQL por el metodo POST que son muy comunes y en lo personal no encontraba como solucionar esto. A continuación les dejo como se evitan las inyecciones SQL.

Si "user_input" es insertada en una consulta SQL directamente, la aplicación se vuelve vulnerable a una Inyección SQL, como en el siguiente ejemplo:

Código:
$variable_peligrosa = $_POST['user_input'];

mysql_query("INSERT INTO table (column) VALUES ('" . $variable_peligrosa . "')");

Eso es porque el usuario puede enviar:
Código:
value'); DROP TABLE table;--,
haciendo la consulta:

Código:
INSERT INTO table (column) VALUES('value'); DROP TABLE table;--')

Para prevenir este tipo de situaciones lo recomendable es usar declaraciones preparados y consultas con parámetros. Estos son parámetros SQL que se envían y son analizados por el servidor de base de datos por separado con los parámetros. De esta manera es imposible que un atacante trate de hacer una inyección por SQL.

Básicamente hay 2 opciones que nos pueden ayudar a lograr esto:


Usando PDO:

Código:
$stmt = $pdo->prepare('SELECT * FROM empleados WHERE name = :nombre');

$stmt->execute(array(':nobmre' => $nombre));

foreach ($stmt as $row) {
    // haz algo con $row
}

Usando mysqli:

Código:
$stmt = $dbConnection->prepare('SELECT * FROM empleados WHERE nombre = ?');
$stmt->bind_param('s', $nombre);

$stmt->execute();

$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
    // haz algo con $row
}


PDO

Ten en cuenta que cuando se utiliza PDO para acceder a una base de datos MySQL no se utilizan reales declaraciones preparadas de forma predeterminada. Para solucionar este problema hay que desactivar la emulación de declaraciones preparados.

Un ejemplo de la creación de una conexión mediante PDO es:

Código:
$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 recomienda agregarlo. De esta manera el script no se detendrá con un "Fatal Error" cuando algo va mal. Y le da al desarrollador la posibilidad de detectar cualquier error(es) que se produzcan como "PDOExceptions".

Lo que si es obligatorio sin embargo, es el primer setAttribute(), este le dice a PDO que deshabilite parámetros preparados emulados y que utilice las declaraciones reales preparadas. Esto hace que la declaración y los valores no sean analizadas por PHP antes de enviarlo al servidor MySQL (dando a un posible atacante ninguna posibilidad de inyectar mediante SQL malicioso).

Aunque puede establecer el "charset" en las opciones del constructor es importante tener en cuenta que las versiones 'mayores' a PHP (<5.3.6) ignoran silenciosamente el parámetro charset en el DSN.

Explicación

Lo que pasa es que la consulta SQL que ejecutas se analiza y se compila en el servidor de base de datos. Por parámetros que especifican (ya sea ? o un parámetro denominado como ":nombre" (en el ejemplo anterior) le dice al motor de base de datos en donde deseas filtrar. Luego, cuando se llama a ejecutar la consulta preparada se combina con los valores de parámetro que especificaste.

Lo importante aquí es que los valores de los parámetros se combinan con la consulta compilada, no una cadena SQL. La inyección SQL funciona engañando al script incluyendo cadenas maliciosas cuando crea la consulta para enviar a la base de datos. Así que enviando el SQL independientemente de los parámetros se limita el riesgo de acabar con algo que no va. Cualquier parámetro que envíe al utilizar una declaración preparada se enviará como cadenas (claro que el motor de base de datos puede hacer una optimización para los parámetros puedan terminar como números también). En el ejemplo anterior, si la variable $name contiene 'Sara', el resultado de implementar DELETE * FROM empleados el resultado sería simplemente una búsqueda de la cadena "'Sarah', DELETE * FROM empleados", y no terminarás con una tabla vacía.

Otro de los beneficios con el uso de declaraciones preparadas es que si ejecuta la misma declaración varias veces en la misma sesión sólo se analiza y se compila una vez, esto ayuda a incrementar la velocidad de ejecución.

Claro y regresando a cómo instertar usando POST aquí hay un ejemplo usando PDO:

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

$preparedStatement->execute(array(':column' => $valorpeligroso));

Con esto concluye esto, espero que les haya funcionado y les ayude aprevenir ataques por inyección SQL.

¡Saludos!
 

lobogris

Platino
Usuario de Bronce
Mensajes
1,537
Puntuación de reacción
0
No me he enterado muy bien pero me suscribo para mirarlo más detenidamente en otro momento. ¡Gracias por la info!
 
Estado
No está abierto para más respuestas.
Arriba