Hola hoy les quiero compartir dos maneras de evitar inyecciones SQL 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:
Eso es porque el usuario puede enviar lo siguiente:
haciendo que la consulta sea la siguiente:
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:
Usando mysqli:
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:
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 "'Sara', 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:
Con esto concluye esto, espero que les haya funcionado y les ayude aprevenir ataques por inyección SQL.
¡Saludos!
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:
Insertar CODE, HTML o PHP:
$variable_peligrosa = $_POST['user_input'];
mysql_query("INSERT INTO table (column) VALUES ('" . $variable_peligrosa . "')");
Eso es porque el usuario puede enviar lo siguiente:
Insertar CODE, HTML o PHP:
value'); DROP TABLE table;--,
haciendo que la consulta sea la siguiente:
Insertar CODE, HTML o PHP:
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:
Insertar CODE, HTML o PHP:
$stmt = $pdo->prepare('SELECT * FROM empleados WHERE name = :nombre');
$stmt->execute(array(':nobmre' => $nombre));
foreach ($stmt as $row) {
// haz algo con $row
}
Usando mysqli:
Insertar CODE, HTML o PHP:
$stmt = $ConexionBD->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:
Insertar CODE, HTML o PHP:
$ConexionBD = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$ConexionBD->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$ConexionBD->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 "'Sara', 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:
Insertar CODE, HTML o PHP:
$declaracionPreparada = $db->prepare('INSERT INTO table (column) VALUES (:column)');
$declaracionPreparada->execute(array(':column' => $valorpeligroso));
Con esto concluye esto, espero que les haya funcionado y les ayude aprevenir ataques por inyección SQL.
¡Saludos!