La vulnerabilidad Cross-Site Request Forgery (CSRF) ocurre en aplicaciones web y le permite a un atacante inducir a los usuarios a realizar acciones que no pretenden realizar, como por ejemplo por ejemplo, cambiar su dirección de correo electrónico, su contraseña o realizar una transferencia de fondos.
Mediante una CSRF, un atacante puede eludir parcialmente la política que evita que diferentes sitios web se interfieran entre sí (Same-Origina Policy).
¿Cuáles son los riesgos de una vulnerabilidad CSRF?
Los riesgos se generan cuando el atacante logra que la víctima lleve a cabo una acción involuntaria. Dependiendo de la acción, el atacante podría obtener el control total sobre la cuenta del usuario.
Por ejemplo, si el usuario comprometido tiene un rol privilegiado dentro de la aplicación, entonces el atacante podría tomar el control total de todos los datos y de las funcionalidades de la aplicación.
¿Cómo funciona una vulnerabilidad CSRF?
Para que un ataque CSRF sea posible, deben cumplirse tres condiciones:
- Existe una acción relevante que el atacante quiere inducir. Puede ser una acción privilegiada (modificar permisos para otros usuarios) o una acción sobre datos específicos del usuario (cambiar la propia contraseña del usuario).
- El manejo de sesiones debe estar basado en cookies dado que realizar una acción implica realizar una o más solicitudes HTTP. Y si la aplicación utiliza cookies de sesión, estas siempre serán enviadas para identificar al usuario que ha realizado las solicitudes.
- Las solicitudes no contienen parámetros impredecibles, es decir, no existen valores que el atacante tenga que determinar o adivinar. Por ejemplo, al hacer que un usuario cambie su contraseña, la función no es vulnerable si un atacante necesita conocer el valor de la contraseña existente.
Ahora veamos cómo se vería en un sistema vulnerable:
- El siguiente sistema nos permite cambiar la clave de un usuario. En este caso, la aplicación no solicita la contraseña anterior, por lo que ya es vulnerable.
- Siguiendo el flujo normal de funcionamiento de la app, observamos que cuando un usuario intenta cambiar su contraseña se realiza una solicitud a la siguiente URL:
http://vulnerablesite.com/vulnerabilities/csrf/?password_new=hackmetrix&password_conf=hackmetrix&Change=Change
- Por último, el usuario recibe como respuesta que la clave fue cambiada.
Analicemos si este escenario cumple con las tres condiciones mencionadas anteriormente.
¿Existe una acción relevante? | Sí, cambiar la contraseña de un usuario. |
¿El manejo de sesiones está basado en cookies? | Sí, utiliza cookies para el manejo de sesiones. |
¿Contiene parámetros impredecibles? | No, no utiliza un parámetro que solicite la clave actual del usuario, como por ejemplo password_current |
En este caso, podemos concluir que esta aplicación tiene la vulnerabilidad CSRF, ya que el atacante podría engañar a un usuario para que acceda a un sitio, que a su vez le indique al navegador realizar una solicitud al sitio vulnerable para que se cambie la contraseña del usuario.
¿Cómo se ve una CSRF en el código?
Este es un ejemplo de cómo se vería la siguiente vulnerabilidad en código PHP.
<?php
if (isset($_GET[‘Change’])) {
// Turn requests into variables
$pass_new = $_GET[‘password_new’];
$pass_conf = $_GET[‘password_conf’];
if (($pass_new == $pass_conf)){
$pass_new = mysql_real_escape_string($pass_new);
$pass_new = md5($pass_new);
$insert=”UPDATE `users` SET password = ‘$pass_new‘ WHERE user = ‘admin’;”;
$result=mysql_query($insert) or die(‘<pre>’ . mysql_error() . ‘</pre>’ );
echo “<pre> Password Changed </pre>“;
mysql_close();
}
else{
echo “<pre> Passwords did not match. </pre>“;
}
}
?>
En este caso, no existen parámetros impredecibles. Los parámetros password_new y password_conf son totalmente predecibles y son los que permiten asignar la nueva clave al usuario.
En cambio, si agregas parámetros impredecibles puedes evitar esta vulnerabilidad. Para este ejemplo, se añadirá el parámetro password_current, el cual contendrá la clave actual del usuario, y por ende, será un parámetro imprescindible para el atacante.
<?php
if (isset($_GET[‘Change’])) {
// Turn requests into variables
$pass_curr = $_GET[‘password_current’];
$pass_new = $_GET[‘password_new’];
$pass_conf = $_GET[‘password_conf’];
// Sanitise current password input
$pass_curr = stripslashes( $pass_curr );
$pass_curr = mysql_real_escape_string( $pass_curr );
$pass_curr = md5( $pass_curr );
// Check that the current password is correct
$qry = “SELECT password FROM `users` WHERE user=’admin’ AND password=’$pass_curr‘;”;
$result = mysql_query($qry) or die(‘<pre>’ . mysql_error() . ‘</pre>’ );
if (($pass_new == $pass_conf) && ( $result && mysql_num_rows( $result ) == 1 )){
$pass_new = mysql_real_escape_string($pass_new);
$pass_new = md5($pass_new);
$insert=“UPDATE `users` SET password = ‘$pass_new‘ WHERE user = ‘admin’;”;
$result=mysql_query($insert) or die(‘<pre>’ . mysql_error() . ‘</pre>’ );
echo “<pre> Password Changed </pre>”;
mysql_close();
}
else{
echo “<pre> Passwords did not match or current password incorrect. </pre>”;
}
}
?>
Remediación del CSRF
Como vimos en la sección anterior, la solución es agregar parámetros impredecibles.
Ahora bien, esta no es la única forma de evitar esta vulnerabilidad, también existen los CSRF Tokens.
El CSRF Token es un valor único, secreto e impredecible que genera la aplicación del lado del servidor y se transmite al cliente de tal manera que se incluye en la siguiente solicitud realizada por el cliente. Cuando se realiza la siguiente solicitud, la aplicación del lado del servidor la valida o la rechaza dependiendo de si incluye el token esperado o no.
Los CSRF Tokens previenen estos ataques dado que el atacante no puede predecir el valor del CSRF token del usuario, no puede construir una solicitud con todos los parámetros necesarios para que la aplicación cumpla con la solicitud.
Un pentest nunca está demás
Los casos en los que puede aparecer esta vulnerabilidad son diversos y, hasta la fecha, no existe una herramienta automatizada que permita detectarla.
Una vez que logres corregir los errores en el código, es recomendable solicitar ayuda externa para realizar pruebas de intrusión minuciosas y efectivas.
En Hackmetrix contamos con un equipo especializado que te ayudará a poder detectar estas fallas y prevenir que futuros agentes maliciosos se aprovechen de ellas.
Conclusión
La vulnerabilidad Cross-Site Request Forgery puede permitirle al atacante que inducir a los usuarios para que realicen acciones que no pretendan realizar.
Evitar estos riesgos es de suma importancia para una empresa ya que podría poner en peligro a los usuarios de la plataforma y, eventualmente, generar una brecha costosa para el negocio.
Por otro lado, para detectar esta vulnerabilidad se requiere del trabajo de una persona calificada que analice, evalúe e interprete la información, por este motivo, es recomendable realizar pruebas de intrusión periódicas para detectarlas de forma temprana.
De todas formas, ahora conoces los métodos de remediación que te ayudarán a resolver este tipo de errores y a tenerlos en cuenta en la escritura de tu código.
Referencias
https://portswigger.net/web-security/csrf
https://portswigger.net/web-security/csrf/tokens
https://owasp.org/www-community/attacks/csrf
https://franc205.medium.com/same-origin-policy-e1533bed9dcd
https://rusyasoft.github.io/java/2019/02/15/spring-security-csrf-from-context/