CSRF (Cross-Site Request Forgery, межсайтовая подделка запроса) — атака, при которой злоумышленник заставляет браузер авторизованного пользователя отправить вредоносный запрос на целевой сайт. CSRF-токен — криптографически случайное значение, которое сервер генерирует для каждой сессии и проверяет в каждом изменяющем состояние запросе. Без токена запрос отклоняется.
Как работает CSRF-атака
Сценарий без защиты:
- Пользователь залогинен на bank.example.com — браузер хранит сессионную куку.
- Пользователь заходит на evil.com, где скрыта форма:
<form action="https://bank.example.com/transfer" method="POST"><input name="amount" value="1000"><input name="to" value="attacker"></form> - JavaScript автоматически отправляет форму. Браузер прикладывает куку bank.example.com.
- Банк видит авторизованный запрос и выполняет перевод.
CSRF-токен разрывает эту цепочку: злоумышленник не знает значения токена (он не в куке, а в теле формы), поэтому не может составить корректный запрос.
Synchronizer Token Pattern
Основной метод защиты:
- При отображении формы сервер генерирует случайный токен (32+ байта из криптографически стойкого генератора) и связывает его с сессией пользователя.
- Токен встраивается в форму скрытым полем:
<input type="hidden" name="csrf_token" value="abc123..."> - При POST-запросе сервер проверяет: токен из тела запроса совпадает с токеном сессии?
- Несовпадение — запрос отклоняется с кодом 403.
Double Submit Cookie
Для stateless (без сессий) API: токен хранится в куке и должен дублироваться в заголовке запроса (X-CSRF-Token). Атакующий может прочитать куку только с того же домена — cross-site запрос не сможет добавить правильный заголовок.
SameSite Cookie
Современные браузеры поддерживают атрибут SameSite для кук:
- SameSite=Strict — кука отправляется только при навигации с того же сайта. Максимальная защита.
- SameSite=Lax — кука отправляется при GET-переходе с других сайтов, но не при POST (значение по умолчанию в Chrome с 2020 года).
- SameSite=None; Secure — кука отправляется всегда (требуется HTTPS).
История
Тип атаки описан в 2000 году, термин CSRF предложил Дж. Ирвин в 2001-м. OWASP включил CSRF в Top 10 уязвимостей в 2007 году. В 2006 году атака использована против ING Direct — банка с активами $60 млрд. В 2020 году Chrome 80 сделал SameSite=Lax значением по умолчанию, что существенно снизило поверхность атаки для современных браузеров.
CSRF в API и современных приложениях
В REST API с JWT-аутентификацией (токен в Authorization заголовке) CSRF-атака невозможна: браузер не добавляет Authorization заголовок автоматически на cross-site запросы. Если токен в куке — CSRF актуален. GraphQL — типичная жертва CSRF при использовании cookie-аутентификации: все мутации через один endpoint POST /graphql, без CSRF-токена атака возможна.
Проверка CSRF-защиты: инструменты Burp Suite и OWASP ZAP автоматически тестируют отсутствие или слабость CSRF-защиты. Тест вручную: убрать CSRF-токен из запроса — сервер должен вернуть 403. В Django: {% csrf_token %} в шаблоне, @csrf_exempt для отдельных view (только для API с токенной auth). Laravel: @csrf в Blade-шаблонах, VerifyCsrfToken middleware.
Встроенная защита во фреймворках
Django, Laravel, Ruby on Rails, Spring Security и большинство современных фреймворков включают CSRF-защиту по умолчанию для всех POST/PUT/DELETE запросов. Для API с токенной аутентификацией (JWT, OAuth) CSRF менее актуален — если токен не хранится в куке, атака невозможна. Проверяй настройки, когда мигрируешь с cookie-based auth на токены.