# CSRF

> Межсайтовая подделка запроса — атака, при которой чужой сайт заставляет браузер жертвы отправить запрос с её cookie; защита — SameSite cookie, CSRF-токены, проверка Origin.

Источник: https://llmdocs.ru/wiki/csrf/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Полное название**: Cross-Site Request Forgery
- **Классификация**: CWE-352
- **Условие атаки**: аутентификация по cookie, которые браузер прикладывает автоматически
- **Последствия**: смена пароля и почты, переводы, изменение настроек от имени жертвы
- **Защита**: SameSite cookie, синхронизирующий токен, проверка Origin, Fetch Metadata
- **Не защищает**: CORS сам по себе, секретная cookie, POST вместо GET
**CSRF** (*Cross-Site Request Forgery*, межсайтовая подделка запроса) — атака, при которой сайт злоумышленника заставляет браузер жертвы отправить запрос на другой сайт, где жертва уже вошла в систему. Браузер автоматически прикладывает к запросу [cookie](https://llmdocs.ru/wiki/cookies-sessions.md) целевого сайта, и сервер воспринимает его как действие самого пользователя: смену пароля или почты, перевод денег, удаление данных. В отличие от [XSS](https://llmdocs.ru/wiki/xss.md), злоумышленник не читает ответ и не выполняет код на сайте — он лишь «нажимает кнопку» руками жертвы.

## Как работает

Пользователь вошёл в интернет-банк, сессия хранится в cookie. Затем он открывает страницу злоумышленника, где есть скрытая форма:

```html
<form action="https://bank.example/transfer" method="POST" id="f">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="50000">
</form>
<script>document.getElementById("f").submit()</script>
```

Браузер отправляет POST-запрос на `bank.example` вместе с сессионной cookie. Если сервер проверяет только cookie, перевод выполнится. Для GET-запросов достаточно даже `<img src="https://site.example/delete?id=1">`.[1]

Атака возможна, когда одновременно выполняются три условия: действие имеет ценность для злоумышленника, аутентификация основана только на том, что браузер прикладывает сам (cookie, HTTP Basic, клиентские сертификаты), и все параметры запроса злоумышленник может угадать.

## Чем защищаться

### SameSite cookie

Атрибут `SameSite` указывает браузеру, отправлять ли cookie при запросах с других сайтов:[3]

| Значение | Поведение |
|---|---|
| `Strict` | cookie не отправляется ни при каких межсайтовых запросах, даже при переходе по ссылке |
| `Lax` | отправляется только при навигации верхнего уровня методом GET (переход по ссылке) |
| `None` | отправляется всегда; требует `Secure` |

```http
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/
```

Современные браузеры по умолчанию считают cookie без атрибута как `Lax`, что закрыло большинство классических атак. Но полагаться только на это не стоит: поведение по умолчанию различается между браузерами, «сайт» определяется по регистрируемому домену (поддомены одного сайта считаются своими), а GET-запросы, меняющие состояние, `Lax` не защищает.

### CSRF-токены

Классическая защита — **синхронизирующий токен**: сервер генерирует случайное непредсказуемое значение, связанное с сессией, и вставляет его в каждую форму. При запросе, меняющем состояние, сервер сверяет токен; сайт злоумышленника не может его узнать.

```html
<form method="POST" action="/settings/email">
  <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
  ...
</form>
```

Для одностраничных приложений токен передают в заголовке (`X-CSRF-Token`). Вариант без хранения на сервере — **double submit cookie**: токен лежит и в cookie, и в заголовке, сервер сравнивает их; надёжнее подписанная версия, привязанная к сессии. Большинство фреймворков включают защиту из коробки: Django, Rails, Laravel, Spring Security; в Flask — расширение Flask-WTF.[5]

### Проверка Origin и Fetch Metadata

Браузер добавляет к межсайтовым запросам заголовки, которые нельзя подделать из JavaScript:

- `Origin` — с какого сайта отправлен запрос; сервер сравнивает его со списком разрешённых;
- `Sec-Fetch-Site: same-origin | same-site | cross-site | none` — заголовки **Fetch Metadata** позволяют одной проверкой отклонить все межсайтовые запросы к изменяющим методам.[4]

```python
if request.method not in ("GET", "HEAD", "OPTIONS"):
    if request.headers.get("Sec-Fetch-Site") not in (None, "same-origin", "none"):
        abort(403)
```

## Частые заблуждения

- **«У нас POST, а не GET»** — формы прекрасно отправляют POST.
- **«У нас настроен CORS»** — [CORS](https://llmdocs.ru/wiki/cors.md) ограничивает чтение ответа JavaScript-кодом, но простые запросы (формы) всё равно доходят до сервера и выполняются.
- **«API принимает JSON»** — запрос с `Content-Type: application/json` с чужого сайта требует preflight и обычно блокируется, но сервер, который принимает и `text/plain` или form-encoded, уязвим.
- **«Токен в cookie — секретный»** — злоумышленнику не нужно знать cookie, их отправляет браузер.

## Когда CSRF не страшен

Если API аутентифицирует запросы токеном в заголовке `Authorization: Bearer ...`, который JavaScript приложения добавляет явно (см. [OAuth 2.0 и OpenID Connect](https://llmdocs.ru/wiki/oauth-oidc.md)), браузер не приложит его к чужому запросу, и классический CSRF невозможен. Однако хранение такого токена в `localStorage` повышает ущерб от XSS — компромисс между угрозами.

Кроме того, любая XSS-уязвимость обходит CSRF-защиту: скрипт на самом сайте может прочитать токен. Поэтому эти защиты дополняют, а не заменяют друг друга.

## Рекомендуемый набор

1. `SameSite=Lax` (или `Strict`) и `Secure`, `HttpOnly` для сессионных cookie.
2. Встроенная CSRF-защита фреймворка для всех изменяющих запросов.
3. Никаких изменений состояния через GET.
4. Проверка `Origin` или `Sec-Fetch-Site` как дополнительный слой.
5. Повторный ввод пароля или [второй фактор](https://llmdocs.ru/wiki/two-factor-auth.md) для критичных действий — смены почты, пароля, вывода денег.

## См. также

- [XSS (как защищаться)](https://llmdocs.ru/wiki/xss.md)
- [Cookie и сессии](https://llmdocs.ru/wiki/cookies-sessions.md)
- [CORS](https://llmdocs.ru/wiki/cors.md)
- [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md)

## Источники

1. [OWASP — Cross-Site Request Forgery Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)
2. [CWE-352: Cross-Site Request Forgery (CSRF)](https://cwe.mitre.org/data/definitions/352.html)
3. [MDN — SameSite cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value)
4. [web.dev — Protect your resources from web attacks with Fetch Metadata](https://web.dev/articles/fetch-metadata)
5. [Django Docs — Cross Site Request Forgery protection](https://docs.djangoproject.com/en/stable/ref/csrf/)
