Перейти к содержимому

CSRF: проверка и ограничения ​

TIP

Это текущая реализация; при переезде на BFF её заменяет Авторизация и CSRF в BFF.

Как проверить защиту руками и чего в ней пока не хватает. Устройство — «Как устроено», поведение по шагам — «Сценарии».

Как проверить curl'ом ​

curl сам хранит cookie в файле и отправляет их, как браузер; заголовок X-CSRF-Token берётся из того же файла. Используйте тестовую учётную запись; файл cookie содержит токены — не публикуйте его.

bash
API=https://cellestial.ru/api/v1
cookie_jar=$(mktemp)
csrf_token() { awk '$6 == "__Host-csrf" { print $7 }' "$cookie_jar"; }

# Анонимный токен: ответ гостю 401, но cookie приходит
curl -si -c "$cookie_jar" "$API/users/me"

# Вход с токеном
curl -i -b "$cookie_jar" -c "$cookie_jar" \
  -H "Origin: https://cellestial.ru" -H "X-CSRF-Token: $(csrf_token)" \
  -H 'Content-Type: application/json' -d '{"login":"<логин>","password":"<пароль>"}' \
  "$API/auth/login"

# Тот же запрос без заголовка — 403 csrf_invalid
curl -i -b "$cookie_jar" -H 'Content-Type: application/json' \
  -d '{"login":"<логин>","password":"<пароль>"}' "$API/auth/login"

rm -f "$cookie_jar"

Чтобы изобразить чужой сайт, замените Origin на https://evil.example. Чтобы изобразить другого пользователя, войдите вторым пользователем в отдельный файл cookie и подставьте его токен в первый файл и в заголовок.

Матрица проверок ​

Прогнана против https://cellestial.ru 07.10.2026 (бэк 4094350). Значения токенов не приводятся.

№ЗапросИтог
1OPTIONS preflight register204, cookie нет
2гость GET /users/me без cookie401 unauthorized, анонимная __Host-csrf
3register без заголовка403 csrf_invalid
4register, заголовок не равен cookie403 csrf_invalid
5register, заголовок без cookie403 csrf_invalid, новая __Host-csrf
6register, Origin: https://evil.example403 csrf_invalid
7register формой x-www-form-urlencoded с токеном400 validation_error
8register корректно201, access_token, refresh_token, подписанная __Host-csrf
9GET /users/me после регистрации200
10refresh со старым анонимным токеном403 csrf_invalid
11refresh корректно204, три новые cookie
12refresh, заголовок от прошлой ротации403 csrf_invalid
13вторая сессия: GET /users/me с анонимной cookie401, cookie не ставится
14вторая сессия: login корректно200, три cookie
15вторая сессия с токеном первой сессии того же пользователя204: подпись — на пользователя
16login с неверным паролем401 invalid_credentials
17logout без заголовка403 csrf_invalid
18logout корректно204, cookie входа стёрты, анонимная __Host-csrf
19GET /users/me после logout401
20refresh после logout401
21logout второй сессии204
22пользователь Б с подписанным токеном пользователя А, refresh403 csrf_invalid
23то же, logout403 csrf_invalid
24вошёл, анонимный токен в cookie и заголовке, refresh403 csrf_invalid, в ответе подписанная __Host-csrf
25то же, logout403 csrf_invalid
26повтор после 24 с новой cookie204
27два refresh одновременно с одной cookie204 и 401 — ограничение

Известные ограничения ​

  • Сессия есть, а __Host-csrf нет — фронт повторяет после 403 только вход и регистрацию, поэтому стартовая проверка сессии уводит на вход, а выход и изменения показывают ошибку (сценарий). Новые пользователи сюда попадают, только если сами удалили cookie; затронуты вошедшие до выкатки CSRF-защиты (07.10.2026, 15:45 по МСК), один раз — перезагрузка возвращает их внутрь. Задача — frontend#34.
  • Две вкладки обновляют сессию одновременно — одна вылетает на вход (сценарий, строка 27). Задача — backend#12.
  • Подпись привязана к пользователю, а не к сессии (строка 15): токен из одной сессии подходит к другой сессии того же пользователя. Так записано в ТЗ backend#4. Гайдлайн РК1 считает такую привязку допустимой, но более слабой: OWASP советует привязывать токен к сессии (csrf.md).