Перейти к содержанию
Innovialabs

Что такое CSRF и как защитить от него веб-приложение

Основы3 мин

Коротко

CSRF — атака, при которой чужой сайт заставляет браузер пользователя отправить запрос в ваше приложение вместе с его cookie. Защита — CSRF-токен или проверка Origin для всех изменяющих запросов плюс SameSite-cookie как дополнительный слой.

Что такое CSRF

CSRF (Cross-Site Request Forgery, подделка межсайтового запроса) — атака, при которой злоумышленник заставляет браузер вошедшего пользователя отправить запрос в ваше приложение. Браузер автоматически прикладывает к запросу cookie сессии, и сервер считает действие легитимным: меняется email, переводятся деньги, удаляются данные.

Ключевая деталь: атакующий не видит ответ и не крадёт cookie. Ему достаточно, чтобы запрос выполнился.

Пример поддельной формы

Допустим, в банке есть форма смены email, которая отправляет POST /account/email. Злоумышленник размещает на своём сайте такую страницу:

<form action="https://bank.example/account/email" method="POST" id="f">
  <input type="hidden" name="email" value="attacker@evil.example">
</form>
<script>document.getElementById('f').submit();</script>

Пользователь, который залогинен в банке, открывает эту страницу — форма отправляется сама. Если сервер проверяет только cookie, email меняется, а дальше атакующий восстанавливает пароль на свой адрес.

Уязвимы любые действия, которые меняют состояние и опираются только на cookie: формы, GET-ссылки с побочными эффектами, API без собственной проверки.

Способы защиты

CSRF-токен (synchronizer token)

Сервер генерирует случайный непредсказуемый токен, привязывает его к сессии и вставляет в каждую форму. При POST, PUT, PATCH, DELETE сервер сверяет токен из тела запроса или заголовка с сохранённым.

Чужой сайт не может прочитать вашу страницу (это запрещает Same-Origin Policy), поэтому не знает токен. Это классический и самый надёжный вариант — большинство фреймворков (Django, Laravel, Rails, Spring Security) включают его из коробки.

Подходит, когда нет серверного хранилища сессий. Токен кладётся в cookie и одновременно отправляется в заголовке или поле формы; сервер проверяет, что значения совпадают. Важно: токен должен быть подписан (HMAC) и привязан к сессии, иначе атакующий, способный записать cookie через поддомен, обойдёт защиту.

Проверка Origin и Referer

Браузер добавляет заголовок Origin к межсайтовым и POST-запросам. Сервер может отклонять изменяющие запросы, если Origin не входит в список ваших доменов. Если Origin отсутствует, можно смотреть на Referer. Современные браузеры также шлют Sec-Fetch-Site, по которому легко отличить same-origin от cross-site.

Это хороший дополнительный слой и простой вариант для API, но запросы без этих заголовков нужно обрабатывать строго — отклонять.

Атрибут SameSite говорит браузеру, отправлять ли cookie при межсайтовых запросах:

ЗначениеПоведениеЗащита от CSRF
Strictcookie не отправляется ни с какими межсайтовыми запросамисильная
Laxотправляется только при переходе по ссылке (GET верхнего уровня)от форм POST защищает
Noneотправляется всегда (требует Secure)нет

Когда SameSite достаточно

SameSite=Lax или Strict закрывает большую часть сценариев, но полагаться только на него стоит лишь при всех условиях сразу:

  • все изменяющие действия идут через POST/PUT/DELETE, а не через GET;
  • у вас нет поддоменов, которые контролирует кто-то другой: SameSite считает «своим» весь сайт (*.example.com), а не конкретный origin;
  • cookie явно выставлены с SameSite, а не оставлены на умолчаниях браузера;
  • пользователи работают в браузерах, которые поддерживают атрибут.

Если хотя бы одно не выполняется — добавьте токены или проверку Origin. Для банков, админок и платёжных операций правильный выбор — токен плюс SameSite.

Частые ошибки

  • Изменение данных через GET (/delete?id=5) — такие ссылки срабатывают даже при SameSite=Lax.
  • Токен проверяется, только если он передан: отсутствие токена должно означать отказ.
  • Один токен на всех пользователей или токен в URL, который утекает через логи и Referer.
  • CORS с Access-Control-Allow-Origin: * и credentials в надежде, что это «защищает» — CORS управляет чтением ответов, а не отправкой запросов.
  • Защищены формы, но забыт JSON API, который принимает text/plain или application/x-www-form-urlencoded.

Подробный разбор мер — в OWASP CSRF Prevention Cheat Sheet.

Частые вопросы

Если токен хранится в JavaScript и добавляется вручную в заголовок, браузер не прикладывает его автоматически, поэтому классический CSRF не работает. Риск возвращается, как только аутентификация переходит в cookie.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.