#Введение
Cross-site request forgery — это тип вредоносной атаки, при которой неавторизованные команды выполняются от имени аутентифицированного пользователя. К счастью, Laravel упрощает защиту вашего приложения от атак cross-site request forgery (CSRF).
#Объяснение уязвимости
Если вы не знакомы с cross-site request forgery, рассмотрим пример, как эта уязвимость может быть использована. Представьте, что в вашем приложении есть маршрут /user/email, который принимает POST запрос для изменения адреса электронной почты аутентифицированного пользователя. Скорее всего, этот маршрут ожидает поле ввода email с новым адресом электронной почты пользователя.
Без защиты от CSRF вредоносный сайт может создать HTML-форму, которая отправляет запрос на маршрут /user/email вашего приложения с адресом электронной почты злоумышленника:
<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>
Если вредоносный сайт автоматически отправит форму при загрузке страницы, злоумышленнику останется лишь заманить ничего не подозревающего пользователя вашего приложения на свой сайт, и адрес электронной почты пользователя будет изменён в вашем приложении.
Чтобы предотвратить эту уязвимость, необходимо проверять каждый входящий POST, PUT, PATCH или DELETE запрос на наличие секретного значения сессии, к которому вредоносное приложение не имеет доступа.
#Предотвращение CSRF-запросов
Laravel автоматически генерирует CSRF «токен» для каждой активной пользовательской сессии, управляемой приложением. Этот токен используется для проверки, что аутентифицированный пользователь действительно инициирует запросы к приложению. Поскольку токен хранится в сессии пользователя и меняется при каждой регенерации сессии, вредоносное приложение не может получить к нему доступ.
Текущий CSRF-токен сессии можно получить через сессию запроса или с помощью хелпера csrf_token:
use Illuminate\Http\Request;
Route::get('/token', function (Request $request) {
$token = $request->session()->token();
$token = csrf_token();
// ...
});
Всякий раз, когда вы определяете HTML-форму с методом "POST", "PUT", "PATCH" или "DELETE" в вашем приложении, необходимо включать скрытое поле CSRF _token в форму, чтобы middleware защиты CSRF мог проверить запрос. Для удобства можно использовать директиву Blade @csrf, которая сгенерирует скрытое поле с токеном:
<form method="POST" action="/profile">
@csrf
<!-- Эквивалентно... -->
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>
App\Http\Middleware\VerifyCsrfToken middleware, который по умолчанию включён в группу middleware web, автоматически проверит, что токен из входящих данных запроса совпадает с токеном, хранящимся в сессии. Если токены совпадают, мы уверены, что запрос инициирован аутентифицированным пользователем.
#CSRF-токены и SPA
Если вы создаёте SPA, использующее Laravel в качестве API-бэкенда, ознакомьтесь с документацией Laravel Sanctum для информации об аутентификации через API и защите от CSRF-уязвимостей.
#Исключение URI из защиты CSRF
Иногда может потребоваться исключить набор URI из защиты CSRF. Например, если вы используете Stripe для обработки платежей и их систему webhook, необходимо исключить маршрут обработчика webhook Stripe из защиты CSRF, так как Stripe не будет отправлять CSRF-токен вашим маршрутам.
Обычно такие маршруты размещают вне группы middleware web, которую App\Providers\RouteServiceProvider применяет ко всем маршрутам в файле routes/web.php. Однако можно также исключить маршруты, добавив их URI в свойство $except middleware VerifyCsrfToken:
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* URI, которые должны быть исключены из проверки CSRF.
*
* @var array
*/
protected $except = [
'stripe/*',
'http://example.com/foo/bar',
'http://example.com/foo/*',
];
}
Для удобства middleware CSRF автоматически отключается для всех маршрутов при запуске тестов.
#X-CSRF-TOKEN
Помимо проверки CSRF-токена в параметрах POST, middleware App\Http\Middleware\VerifyCsrfToken также проверяет заголовок запроса X-CSRF-TOKEN. Например, вы можете хранить токен в HTML-теге meta:
<meta name="csrf-token" content="{{ csrf_token() }}">
Затем можно настроить библиотеку, например jQuery, чтобы она автоматически добавляла токен во все заголовки запросов. Это обеспечивает простую и удобную защиту CSRF для AJAX-приложений, использующих устаревшие JavaScript-технологии:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
#X-XSRF-TOKEN
Laravel сохраняет текущий CSRF-токен в зашифрованном cookie XSRF-TOKEN, который включается в каждый ответ, сгенерированный фреймворком. Значение этого cookie можно использовать для установки заголовка запроса X-XSRF-TOKEN.
Этот cookie в первую очередь предназначен для удобства разработчиков, так как некоторые JavaScript-фреймворки и библиотеки, например Angular и Axios, автоматически помещают его значение в заголовок X-XSRF-TOKEN при запросах к тому же источнику.
По умолчанию файл resources/js/bootstrap.js включает HTTP-библиотеку Axios, которая автоматически отправляет заголовок X-XSRF-TOKEN.