Джерело: https://laravelukraine.com/docs/13.x/csrf

# Захист від CSRF

- [Вступ](#csrf-introduction)
- [Запобігання CSRF-запитам](#preventing-csrf-requests)
    - [Перевірка джерела](#origin-verification)
    - [Виключення URI](#csrf-excluding-uris)
- [X-CSRF-Token](#csrf-x-csrf-token)
- [X-XSRF-Token](#csrf-x-xsrf-token)

<a name="csrf-introduction"></a>
## Вступ

Міжсайтова підробка запитів - це різновид зловмисної атаки, за якої від імені автентифікованого користувача виконуються несанкціоновані команди. На щастя, Laravel спрощує захист вашого застосунку від атак [міжсайтової підробки запитів](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF).

<a name="csrf-explanation"></a>
#### Пояснення вразливості

Якщо ви не знайомі з міжсайтовою підробкою запитів, розгляньмо приклад того, як цю вразливість можна використати. Уявіть, що ваш застосунок має маршрут `/user/email`, який приймає `POST`-запит для зміни адреси електронної пошти автентифікованого користувача. Найімовірніше, цей маршрут очікує поле `email` із адресою, яку користувач хоче почати використовувати.

Без захисту від CSRF зловмисний сайт міг би створити HTML-форму, що вказує на маршрут `/user/email` вашого застосунку й надсилає власну адресу зловмисника:

```blade
<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` на наявність секретного значення сесії, доступу до якого зловмисний застосунок не має.

<a name="preventing-csrf-requests"></a>
## Запобігання CSRF-запитам

[`Middleware`](/docs/{{version}}/middleware) `Illuminate\Foundation\Http\Middleware\PreventRequestForgery`, який за замовчуванням входить до групи `web`, захищає ваш застосунок від міжсайтової підробки запитів двошаровим підходом.

Спершу `middleware` перевіряє заголовок браузера `Sec-Fetch-Site`. Сучасні браузери автоматично встановлюють цей заголовок для кожного запиту, вказуючи, чи походить він із того самого джерела (origin), того самого сайту, чи з міжсайтового джерела. Якщо заголовок свідчить, що запит надійшов із того самого джерела, його одразу пропускають без жодної перевірки токена.

Якщо перевірка джерела не проходить - наприклад, тому що запит надходить зі старішого браузера, який не надсилає заголовок `Sec-Fetch-Site`, або тому що з'єднання не є захищеним, - `middleware` повертається до традиційної перевірки CSRF-токена.

Laravel автоматично генерує CSRF-«токен» для кожної активної [сесії користувача](/docs/{{version}}/session), якою керує застосунок. Цей токен використовується, щоб перевірити, що запити до застосунку робить саме автентифікований користувач. Оскільки токен зберігається в сесії користувача й змінюється щоразу, коли сесію регенеровано, зловмисний застосунок не може отримати до нього доступ.

Доступ до CSRF-токена поточної сесії можна отримати через сесію запиту або через функцію-хелпер `csrf_token`:

```php
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`, яка згенерує приховане поле з токеном:

```blade
<form method="POST" action="/profile">
    @csrf

    <!-- Equivalent to... -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>
```

<a name="csrf-tokens-and-spas"></a>
#### CSRF-токени та SPA

Якщо ви створюєте SPA, що використовує Laravel як бекенд для API, зверніться до [документації Laravel Sanctum](/docs/{{version}}/sanctum) по інформацію про автентифікацію з вашим API та захист від CSRF-вразливостей.

<a name="origin-verification"></a>
### Перевірка джерела

Як зазначено вище, `middleware` захисту від підробки запитів спершу перевіряє заголовок `Sec-Fetch-Site`, щоб визначити, чи надійшов запит із того самого джерела. За замовчуванням, якщо ця перевірка не проходить, `middleware` повертається до перевірки CSRF-токена.

Однак якщо ви хочете покладатися виключно на перевірку джерела й повністю вимкнути запасну перевірку токена, скористайтеся методом `preventRequestForgery` у файлі `bootstrap/app.php` вашого застосунку:

```php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(originOnly: true);
})
```

У режимі перевірки лише за джерелом запити, які не пройшли цю перевірку, отримають HTTP-відповідь `403` замість відповіді `419`, яку зазвичай пов'язують із розбіжністю CSRF-токенів.

> [!WARNING]
> Заголовок `Sec-Fetch-Site` браузери надсилають лише через захищені (HTTPS) з'єднання. Якщо ваш застосунок працює не через HTTPS, перевірка джерела буде недоступна, і `middleware` повернеться до перевірки CSRF-токена.

Якщо ваш застосунок має приймати запити з піддоменів (наприклад, `dashboard.example.com` приймає запити від `example.com`), ви можете дозволити запити з того самого сайту на додачу до запитів із того самого джерела:

```php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(allowSameSite: true);
})
```

<a name="csrf-excluding-uris"></a>
### Виключення URI із захисту від CSRF

Іноді вам може знадобитися виключити набір URI із захисту від CSRF. Наприклад, якщо ви використовуєте [Stripe](https://stripe.com) для обробки платежів і користуєтеся їхньою системою вебхуків, вам доведеться виключити маршрут обробника вебхуків Stripe із захисту від CSRF, адже Stripe не знатиме, який CSRF-токен надсилати до ваших маршрутів.

Зазвичай такі маршрути варто розміщувати поза групою `middleware` `web`, яку Laravel застосовує до всіх маршрутів у файлі `routes/web.php`. Утім, ви також можете виключити конкретні маршрути, передавши їхні URI методу `preventRequestForgery` у файлі `bootstrap/app.php` вашого застосунку:

```php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(except: [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ]);
})
```

> [!NOTE]
> Для зручності CSRF-`middleware` автоматично вимикається для всіх маршрутів під час [запуску тестів](/docs/{{version}}/testing).

<a name="csrf-x-csrf-token"></a>
## X-CSRF-TOKEN

Крім перевірки CSRF-токена як POST-параметра, `middleware` `PreventRequestForgery` також перевіряє заголовок запиту `X-CSRF-TOKEN`. Ви можете, наприклад, зберігати токен у HTML-тегу `meta`:

```blade
<meta name="csrf-token" content="{{ csrf_token() }}">
```

Далі ви можете вказати бібліотеці на кшталт jQuery автоматично додавати токен до всіх заголовків запитів. Це дає простий і зручний захист від CSRF для ваших AJAX-застосунків, що використовують застарілі JavaScript-технології:

```js
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
```

<a name="csrf-x-xsrf-token"></a>
## X-XSRF-TOKEN

Laravel зберігає поточний CSRF-токен у зашифрованій cookie `XSRF-TOKEN`, яка додається до кожної відповіді, згенерованої фреймворком. Ви можете використати значення цієї cookie, щоб задати заголовок запиту `X-XSRF-TOKEN`.

Цю cookie надсилають насамперед задля зручності розробників, оскільки деякі JavaScript-фреймворки та бібліотеки - як-от Angular і Axios - автоматично підставляють її значення в заголовок `X-XSRF-TOKEN` для запитів із того самого джерела.