Protección CSRF
Introducción
Las falsificaciones de peticiones entre sitios son un tipo de exploit malicioso mediante el cual se ejecutan comandos no autorizados en nombre de un usuario autenticado. Afortunadamente, Laravel hace que sea fácil de proteger su aplicación contra ataques de falsificación de petición de sitio cruzado (CSRF).
Explicación de la vulnerabilidad
En caso de que no estés familiarizado con las falsificaciones de peticiones entre sitios, vamos a exponer un ejemplo de cómo esta vulnerabilidad puede ser explotada. Imagina que tu aplicación tiene una ruta /user/email
que acepta una petición POST
para cambiar la dirección de correo electrónico del usuario autenticado. Lo más probable es que esta ruta espere que un campo de entrada de email
contenga la dirección de correo electrónico que al usuario le gustaría empezar a utilizar.
Sin protección CSRF, un sitio web malicioso podría crear un formulario HTML que apunte a la ruta /user/email
de su aplicación y envíe la propia dirección de correo electrónico del usuario malicioso:
<form action="https://your-application.com/user/email" method="POST"> <input type="email" value="malicious-email@example.com"></form> <script> document.forms[0].submit();</script>
Si el sitio web malicioso envía automáticamente el formulario cuando se carga la página, el usuario malicioso sólo tiene que atraer a un usuario desprevenido de tu aplicación para que visite su sitio web y su dirección de correo electrónico se cambiará en la aplicación.
Para prevenir esta vulnerabilidad, necesitamos inspeccionar cada petición POST
, PUT
, PATCH
, o DELETE
entrante en busca de un valor de sesión secreto al que la aplicación maliciosa no pueda acceder.
Prevención de solicitudes CSRF
Laravel genera automáticamente un "token" CSRF para cada sesión de usuario activa gestionada por la aplicación. Este token se utiliza para verificar que el usuario autenticado es la persona que realmente realiza las peticiones a la aplicación. Como este token se almacena en la sesión del usuario y cambia cada vez que se regenera la sesión, una aplicación maliciosa no puede acceder a él.
Se puede acceder al token CSRF de la sesión actual a través de la sesión de la petición o a través de la función de ayuda csrf_token
:
use Illuminate\Http\Request; Route::get('/token', function (Request $request) { $token = $request->session()->token(); $token = csrf_token(); // ...});
Cada vez que defina un formulario HTML "POST", "PUT", "PATCH" o "DELETE" en su aplicación, debe incluir un campo oculto CSRF _token
en el formulario para que el middleware protección CSRF pueda validar la solicitud. Para mayor comodidad, puede utilizar la directiva @csrf
Blade para generar el campo de entrada de token oculto:
<form method="POST" action="/profile"> @csrf <!-- Equivalent to... --> <input type="hidden" name="_token" value="{{ csrf_token() }}" /></form>
El middleware App\Http\middleware\VerifyCsrfToken
, que está incluido en el grupo de middleware web
por defecto, verificará automáticamente que el token en la entrada de la petición coincide con el token almacenado en la sesión. Cuando estos dos tokens coinciden, sabemos que el usuario autenticado es el que inicia la petición.
Tokens CSRF y SPAs
Si estás construyendo una SPA que utiliza Laravel como API backend, deberías consultar la documentación de Laravel Sanctum para obtener información sobre la autenticación con tu API y la protección contra vulnerabilidades CSRF.
Excluir URIs de la protección CSRF
A veces puede que desee excluir un conjunto de URIs de la protección CSRF. Por ejemplo, si está utilizando Stripe para procesar pagos y está utilizando su sistema de webhooks, necesitará excluir su ruta de gestión de webhooks de Stripe de la protección CSRF ya que Stripe no sabrá qué token CSRF enviar a sus rutas.
Normalmente, debe colocar este tipo de rutas fuera del grupo de middleware web
que App\Providers\RouteServiceProvider
aplica a todas las rutas en el archivo routes/web.php
. Sin embargo, también puede excluir las rutas añadiendo sus URIs a la propiedad $except
del middleware VerifyCsrfToken
:
<?php namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware{ /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ 'stripe/*', 'http://example.com/foo/bar', 'http://example.com/foo/*', ];}
Nota
Para mayor comodidad, el middleware CSRF se desactiva automáticamente para todas las rutas cuando se ejecutan tests.
X-CSRF-TOKEN
Además de comprobar el token CSRF como parámetro POST, el middleware App\Http\Middleware\VerifyCsrfToken
también comprobará la cabecera de petición X-CSRF-TOKEN
. Podría, por ejemplo, almacenar el token en una etiqueta meta
de HTML:
<meta name="csrf-token" content="{{ csrf_token() }}">
A continuación, puede indicar a una biblioteca como jQuery que añada automáticamente el token a todas las cabeceras de solicitud. Esto proporciona una protección CSRF simple y conveniente para sus aplicaciones basadas en AJAX que utilizan tecnología JavaScript heredada:
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }});
X-XSRF-TOKEN
Laravel almacena el token CSRF actual en una cookie XSRF-TOKEN
cifrada que se incluye en cada respuesta generada por el framework. Puedes utilizar el valor de la cookie para establecer la cabecera de petición X-XSRF-TOKEN
.
Esta cookie se envía principalmente para comodidad del desarrollador, ya que algunos frameworks y bibliotecas JavaScript, como Angular y Axios, colocan automáticamente su valor en la cabecera X-XSRF-TOKEN
en las solicitudes con el mismo origen.
Nota
Por defecto, el archivoresources/js/bootstrap.js
incluye la librería HTTP Axios que enviará automáticamente la cabeceraX-XSRF-TOKEN
por ti.