Guía Rápida: Seguridad Básica en PHP
El Cross-Site Request Forgery (CSRF), o Falsificación de Solicitudes entre Sitios, es un ataque en el que un atacante engaña a un usuario autenticado para que ejecute acciones no deseadas en un sitio web en el que el usuario está autenticado, sin su conocimiento. Este tipo de ataque puede tener consecuencias graves, como la modificación de datos, cambios de contraseñas o la realización de pagos no autorizados.
Para proteger tus aplicaciones PHP de este tipo de ataques, debes asegurarte de que las solicitudes críticas (como el envío de formularios de autenticación, cambio de contraseñas, eliminación de cuentas, etc.) provengan de una fuente legítima y no de un atacante. Esto se logra implementando protección CSRF mediante tokens únicos en los formularios.
¿Qué es un Ataque CSRF?
Un ataque CSRF ocurre cuando un atacante engaña a un usuario para que envíe una solicitud HTTP no deseada a una página web en la que el usuario está autenticado. Esto puede suceder, por ejemplo, si el usuario tiene una sesión activa en su navegador en una aplicación web vulnerable. Si el atacante conoce la URL de una acción importante (como cambiar la contraseña o realizar una compra) y engaña al usuario para que la ejecute (por ejemplo, mediante un enlace malicioso o un formulario), la solicitud será aceptada como si proviniera del usuario legítimo, ya que la sesión de ese usuario está activa.
Ejemplo de un Ataque CSRF:
Supongamos que un usuario está autenticado en un sitio web de banca en línea y tiene una sesión activa. El atacante crea un enlace malicioso en otro sitio web que se ve algo como esto:
<form action="https://mi-banco.com/cambiar-contraseña" method="POST">
<input type="hidden" name="nueva_contraseña" value="1234secreta" />
<input type="submit" value="Cambia tu contraseña" />
</form>
Si el usuario visita la página del atacante, el formulario se enviará sin que el usuario lo sepa ni lo consienta, cambiando la contraseña del banco sin su autorización.
Protección CSRF: Tokens Únicos en Formularios
La forma más común de prevenir ataques CSRF es mediante el uso de tokens CSRF. Un token CSRF es un valor único y aleatorio que se incluye en cada formulario. Este token se genera cuando el formulario se carga y se valida cuando se envía. Si el token no coincide con el valor esperado, la solicitud es rechazada, protegiendo así al usuario contra ataques CSRF.
Cómo Implementar Protección Contra CSRF en PHP
A continuación, veremos cómo implementar protección CSRF en tus aplicaciones PHP utilizando tokens.
1. Generación de un Token CSRF
El primer paso es generar un token único para cada formulario que deseas proteger contra CSRF. Este token debe ser único para cada sesión de usuario y debe ser difícil de predecir para evitar ataques.
Generación del Token CSRF:
Puedes generar un token aleatorio utilizando la función bin2hex(random_bytes()), que proporciona una manera segura y eficiente de generar un token aleatorio.
// Iniciar la sesión para asociar el token con la sesión de usuario
session_start();
// Generar un token CSRF único si no existe ya uno en la sesión
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // 32 bytes = 64 caracteres hexadecimales
}
Este token debe ser almacenado en la sesión del usuario, ya que será verificado cuando el formulario sea enviado.
2. Incluir el Token en los Formularios
Una vez que hayas generado el token, debes incluirlo en cada formulario como un campo oculto. Esto permitirá que el token se envíe junto con los datos del formulario.
<form action="procesar_formulario.php" method="POST">
<!-- Incluir el token CSRF como un campo oculto -->
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
<!-- Otros campos del formulario -->
<label for="email">Correo electrónico:</label>
<input type="email" name="email" required>
<button type="submit">Enviar</button>
</form>
En este formulario, el token CSRF se envía como parte de los datos del formulario, pero es invisible para el usuario.
3. Validación del Token CSRF al Procesar el Formulario
Cuando el formulario se envíe, deberás validar que el token recibido en la solicitud coincida con el token almacenado en la sesión del usuario. Si los tokens coinciden, puedes continuar procesando el formulario. Si no coinciden, rechaza la solicitud y evita que se realicen cambios no autorizados.
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Comprobar si el token CSRF enviado coincide con el token almacenado en la sesión
if (isset($_POST['csrf_token']) && $_POST['csrf_token'] === $_SESSION['csrf_token']) {
// El token es válido, procesar el formulario
$email = $_POST['email'];
// Realizar la acción deseada (por ejemplo, guardar el email)
echo "Formulario enviado correctamente.";
} else {
// El token no es válido, posible ataque CSRF
die("Solicitud no válida. Token CSRF no coincide.");
}
}
En este fragmento de código, se comprueba que el token enviado en el formulario (a través de $_POST['csrf_token']) coincida con el token almacenado en la sesión. Si no coinciden, la solicitud se bloquea.
4. Eliminar el Token CSRF Después de su Uso
Es recomendable eliminar o regenerar el token CSRF después de que se haya validado y usado, para evitar que un token antiguo sea reutilizado en futuros formularios.
// Después de procesar el formulario, elimina el token CSRF para evitar su reutilización
unset($_SESSION['csrf_token']);
Buenas Prácticas en la Implementación de Protección CSRF
- Uso de HTTPS: Asegúrate de que tu aplicación esté utilizando HTTPS para cifrar las comunicaciones entre el cliente y el servidor, lo que previene que los tokens CSRF sean interceptados por atacantes.
- Generación de Tokens Únicos por Sesión: Genera un token único para cada sesión de usuario. No reutilices los mismos tokens entre sesiones, ya que esto puede facilitar ataques CSRF.
- Incluir el Token en Todos los Formularios: Asegúrate de incluir el token CSRF en todos los formularios importantes (por ejemplo, los formularios de inicio de sesión, modificación de contraseñas, eliminación de cuentas).
- Validación del Token en Todas las Solicitudes Críticas: Siempre valida el token CSRF antes de procesar solicitudes críticas. Nunca confíes en que la solicitud proviene de un origen legítimo sin antes validar el token.
- Regeneración del Token Después de su Uso: Una vez que un token se ha usado para procesar un formulario, es buena práctica destruirlo o generar uno nuevo para evitar ataques de reutilización.
Conclusión
La protección contra CSRF es fundamental para proteger tus aplicaciones web de ataques que podrían realizar acciones no autorizadas en nombre de tus usuarios. Implementando un sistema de tokens CSRF, puedes asegurarte de que las solicitudes provengan de fuentes legítimas, evitando que los atacantes puedan ejecutar acciones maliciosas. Siguiendo las prácticas recomendadas en este tutorial, puedes mejorar la seguridad de tus aplicaciones PHP y proteger a tus usuarios de posibles amenazas.