CSRF: как работают атака и защитные токены
CSRF позволяет чужому сайту отправить запрос от имени уже вошедшего пользователя: браузер сам приложит его cookie. Разбираем, как токен останавливает такую атаку, почему он не заменяет авторизацию и где защита даёт сбой.

Если пользователь вошёл в интернет-банк, а затем открыл вредоносную страницу, браузер может отправить запрос к банку вместе с его cookie. Так работает CSRF — подделка межсайтового запроса. Токен защиты мешает атакующему сформировать такой запрос, но не подтверждает личность пользователя и не спасает от XSS. Ниже — механизм на примере Django 5.2 и общие правила, которые работают независимо от фреймворка.
Почему браузер отправляет запрос за атакующего
Сервер обычно узнаёт пользователя по cookie сессии. Браузер автоматически прикладывает подходящие cookie к запросу — в том числе если переход к вашему сайту начался со страницы другого домена. Для сервера такой запрос может выглядеть как обычное действие вошедшего пользователя.
Предположим, сайт принимает перевод денег через POST-запрос. Атакующая страница не обязана прочитать ответ сервера: достаточно заставить браузер отправить запрос с известными атакующему параметрами. Если сервер полагается только на cookie и не проверяет происхождение действия, он может выполнить перевод.
Ограничение политики одного источника обычно не позволяет чужой странице прочитать ответ, но не запрещает все виды межсайтовых запросов. Поэтому «атакующий не увидит страницу» — не защита от CSRF.
CSRF эксплуатирует не украденный пароль, а доверие сервера к запросу, который браузер отправил вместе с уже имеющимися учётными данными.
Что именно доказывает токен
Защита добавляет к изменяющему состояние запросу значение, которое атакующий сайт не может получить и подставить. Сервер проверяет его и отклоняет запрос, если токен отсутствует или не проходит проверку. Важно: токен не секрет пользователя и не доказательство его личности. Это проверка, что запрос прошёл через ожидаемый интерфейс сайта.
Типичный поток выглядит так:
- Браузер получает страницу с формой, а сервер помещает в неё CSRF-токен.
- При отправке формы браузер передаёт токен вместе с запросом. Для обычной HTML-формы это часто скрытое поле; для JavaScript-клиента — заголовок.
- Сервер сопоставляет полученное значение с ожидаемым и проверяет запрос. При несовпадении действие не выполняется.
Атакующая страница может инициировать запрос, но обычно не может прочитать токен с вашего сайта из-за ограничений браузера. Без этого значения запрос не проходит проверку.
Два распространённых способа хранения
Синхронизированный токен
Сервер хранит секрет или связанное с сессией значение, а клиент передаёт проверяемую форму токена. Такой подход удобно связывать с серверной сессией. В Django 5.2 токен может передаваться в шаблоне через тег защиты формы, а промежуточный слой проверяет небезопасные запросы. Для форм, отправляемых через AJAX, токен обычно передают в заголовке. Конкретное имя и настройка зависят от фреймворка.
Double-submit cookie
Сервер устанавливает cookie с токеном, а клиент отдельно возвращает то же значение — например, в заголовке. Сервер сравнивает два канала. Сам по себе простой вариант ненадёжен, если атакующий способен установить cookie для целевого домена. Более строгая реализация связывает токен с секретом сервера или сессией.
Не путайте эту схему с правилом «есть cookie — значит всё безопасно»: браузер автоматически отправляет cookie, поэтому проверка только cookie не доказывает, что запрос пришёл через вашу страницу.
Где чаще всего ошибаются
- Оставляют изменяющие состояние GET-запросы. Ссылку или изображение можно загрузить с чужой страницы. GET должен читать данные, а не удалять запись или менять настройки.
- Проверяют токен не на всех путях. Исключённый endpoint, отдельный API или старый обработчик формы может остаться без защиты. Проверяйте весь набор маршрутов, которые меняют состояние.
- Считают CORS заменой CSRF-защите. CORS управляет доступом к ответам и некоторыми типами запросов, но сам по себе не гарантирует, что нежелательное действие невозможно инициировать.
- Отключают проверку для устранения ошибки. Сначала выясните, почему запрос не содержит ожидаемый токен: страница могла устареть, cookie — не отправиться, а JavaScript-клиент — не добавить заголовок.
- Забывают про XSS. Если атакующий выполняет JavaScript на вашем домене, он может получить доступ к токену страницы или отправить запрос из доверенного контекста. CSRF-токен не заменяет защиту от XSS.
Дополнительные барьеры и их пределы
Cookie с атрибутом SameSite ограничивает отправку cookie в некоторых межсайтовых сценариях. Это полезный дополнительный барьер, но поведение зависит от значения атрибута, браузера и схемы перехода. Он не отменяет проверку CSRF-токена там, где запрос меняет состояние и использует cookie-аутентификацию.
Проверка заголовков Origin или Referer тоже может помочь выявить запрос не с вашего сайта. Но заголовки могут отсутствовать в отдельных сценариях, поэтому серверу нужно определить, что делать при их отсутствии. Не превращайте дополнительную проверку в единственную защиту без анализа клиентских сценариев.
Для API, где клиент явно передаёт токен авторизации в заголовке и браузер не прикладывает аутентификацию автоматически, классический риск CSRF может быть ниже. Но если API использует cookie, его нужно рассматривать как потенциально уязвимый к CSRF. Архитектура авторизации важнее названия интерфейса — «API» не означает автоматически «безопасно».
| Защита | Что даёт | Чего не гарантирует |
|---|---|---|
| CSRF-токен | Отсекает запросы без значения, доступного через ваш сайт | Не защищает от XSS и не заменяет авторизацию |
SameSite | Ограничивает отправку cookie в межсайтовых сценариях | Не покрывает все контексты и не заменяет токен |
Проверка Origin/Referer | Помогает проверить источник запроса | Требует обработки отсутствующих заголовков и совместимости клиентов |
Как проверить защиту в приложении
- Составьте список всех операций, которые меняют данные: не только формы, но и действия в панели управления и запросы из JavaScript.
- Убедитесь, что такие операции используют методы, предназначенные для изменения состояния, а не GET.
- Проверьте, что шаблоны и клиентский код передают токен, а сервер проверяет его на каждом соответствующем маршруте.
- Повторите запрос без токена и с изменённым токеном. Сервер должен отказать и не выполнить действие.
- Проверьте вход, выход и смену сессии: после таких событий ранее открытая форма может устареть. Ошибка в этом сценарии не повод отключать защиту.
В Django 5.2 проверку CSRF обычно обеспечивает встроенное middleware; для POST-форм в шаблонах используют тег csrf_token. Если вы используете иной способ отправки формы или исключение из проверки, сверяйтесь с документацией именно вашей версии. Не копируйте имя настройки из случайного примера: поведение и параметры зависят от фреймворка.
Термин: same-site и same-origin
Same-origin1 — совпадение схемы, хоста и порта. Same-site — более широкое понятие, связанное с сайтом и его доменной схемой. Поэтому два адреса могут быть разными origin, но относиться к одному site. Это различие важно при настройке cookie и проверках браузера.
1 Например, разные поддомены могут иметь разные origin, хотя браузер может считать их одним site для отдельных правил cookie.
Что делать дальше
Начните с карты изменяющих состояние маршрутов и проверьте каждый тестом без токена. Затем проверьте атрибуты cookie и клиентские запросы в актуальной документации вашего фреймворка. В эксплуатации отслеживайте отказы CSRF-проверки: всплеск ошибок может указывать на устаревшие формы, некорректную интеграцию клиента или внезапное изменение сценария входа.
Инфобез и 152-ФЗ: Аудит политик конфиденциальности, правила сбора cookie.
Спросить за 20 ₽Источники: Django 5.2: Cross Site Request Forgery protection, OWASP Cross-Site Request Forgery Prevention Cheat Sheet
Частые вопросы
CSRF означает, что злоумышленник узнал мой пароль?
Токен CSRF можно хранить в cookie?
Достаточно ли поставить SameSite на cookie?
Почему сервер отклоняет форму с правильным токеном?
Нужна ли CSRF-защита API?
Если токен защищает запрос, значит ли это, что пользователь авторизован?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.