Skip to content

Класс CsrfGuard

Защита форм от подделки межсайтового запроса (CSRF).

Токен не хранится на сервере: он состоит из метки времени и HMAC-SHA256 от секрета по паре «метка времени плюс идентификатор сессии». Проверка - это пересчёт подписи, поэтому схема переживает перезапуск приложения и работает при нескольких рабочих процессах без общего хранилища.

Токен привязан к сессии: выданный одному посетителю не подойдёт другому. И ограничен по времени: подсмотренный однажды перестаёт работать.

bsl
Защита = View.СоздатьЗащитуCSRF(ПолучитьПеременнуюСреды("APP_SECRET"));
// то же самое напрямую
Защита = Новый CsrfGuard(ПолучитьПеременнуюСреды("APP_SECRET"));

Конструктор

bsl
Новый CsrfGuard(Знач Секрет, Знач СрокЖизни = 3600)
ПараметрТипОписание
СекретСтрокаСекрет приложения. Одинаковый у всех рабочих процессов, разный в разных окружениях
СрокЖизниЧислоСрок жизни токена в секундах

Пустой секрет и неположительный срок жизни дают исключение: это ошибки настройки приложения, а не внештатные ситуации во время работы. Секрет в исходный код не помещается.

Свойства

СвойствоТипОписание
СрокЖизниТокенаЧислоСрок жизни токена в секундах

Методы

МетодВозвращаетНазначение
СоздатьТокенСтрокаТокен для сессии
ПроверитьТокенБулевоПроверка токена
ПолеФормыСтрокаГотовое скрытое поле формы
ИмяПоляСтрока_csrf
ИмяЗаголовкаСтрокаX-CSRF-Token
ТокенИзЗаголовковСтрокаТокен из заголовков запроса

СоздатьТокен

bsl
Функция СоздатьТокен(Знач ИдентификаторСессии, Знач МеткаВремени = Неопределено) Экспорт

Выдаёт токен для сессии.

Параметры

ПараметрТипОписание
ИдентификаторСессииСтрокаИдентификатор сессии посетителя
МеткаВремениЧислоВремя выдачи в секундах Unix. По умолчанию текущее время

Возвращаемое значение: Строка - токен вида <метка времени>.<подпись>.

Пустой идентификатор сессии даёт исключение: токен без привязки к сессии не защищает ни от чего. Явная метка времени делает выдачу и проверку воспроизводимыми - это нужно в тестах и при разборе инцидентов.

bsl
Токен = Защита.СоздатьТокен(Запрос.Сессия.Идентификатор());
// 1785876773.940be1dbf278fd7cfd73657aab5195d8882616282dd36368527a4965f5a55e97

ПроверитьТокен

bsl
Функция ПроверитьТокен(Знач Токен, Знач ИдентификаторСессии, Знач ТекущаяМетка = Неопределено) Экспорт

Проверяет токен. Не выбрасывает исключений: любое неожиданное значение - это просто непройденная проверка.

Параметры

ПараметрТипОписание
ТокенСтрокаПроверяемый токен
ИдентификаторСессииСтрокаИдентификатор сессии посетителя
ТекущаяМеткаЧислоВремя проверки в секундах Unix. По умолчанию текущее время

Возвращаемое значение: Булево - Истина, если токен выдан этой сессии и не истёк.

Проверка не проходит, если токен пустой или не строка, нет разделителя, метка времени не из цифр или длиннее 12 символов, метка из будущего, срок жизни истёк, подпись не совпала, идентификатор сессии пустой.

Подписи сравниваются за постоянное время, поэтому по длительности проверки подпись не подобрать. Метку ставит сервер по своим часам, поэтому токен из будущего считается поддельным.

bsl
Токен = Запрос.ПараметрыИменные[Защита.ИмяПоля()];

Если Не Защита.ПроверитьТокен(Токен, Запрос.Сессия.Идентификатор()) Тогда
	Ответ.УстановитьСостояние(403);
	Возврат;
КонецЕсли;

ПолеФормы

bsl
Функция ПолеФормы(Знач ИдентификаторСессии) Экспорт

Готовое скрытое поле формы с токеном. Значения экранируются, поле вставляется в шаблон как есть.

Параметры

ПараметрТипОписание
ИдентификаторСессииСтрокаИдентификатор сессии посетителя

Возвращаемое значение: Строка - разметка input type="hidden".

bsl
Модель.Вставить("ПолеCSRF", Защита.ПолеФормы(Запрос.Сессия.Идентификатор()));
html
<form hx-post="/задачи">
	{{ Модель.ПолеCSRF }}
	<input name="название">
</form>

ИмяПоля

bsl
Функция ИмяПоля() Экспорт

Возвращаемое значение: Строка - _csrf. Имя поля формы, в котором ожидается токен.

bsl
Токен = Запрос.ПараметрыИменные[Защита.ИмяПоля()];

ИмяЗаголовка

bsl
Функция ИмяЗаголовка() Экспорт

Возвращаемое значение: Строка - X-CSRF-Token. Имя заголовка, в котором ожидается токен.

Для запросов htmx токен удобно передавать заголовком сразу для всех форм страницы:

html
<body hx-headers='{"X-CSRF-Token": "{{ Модель.ТокенCSRF }}"}'>

ТокенИзЗаголовков

bsl
Функция ТокенИзЗаголовков(Знач Заголовки) Экспорт

Извлекает токен из заголовков запроса независимо от регистра имени.

Параметры

ПараметрТипОписание
ЗаголовкиСоответствие, СтруктураЗаголовки запроса

Возвращаемое значение: Строка - значение заголовка либо пустая строка.

bsl
Если Не Защита.ПроверитьТокен(Защита.ТокенИзЗаголовков(Запрос.Заголовки), Сессия.Идентификатор()) Тогда
	Ответ.УстановитьСостояние(403);
КонецЕсли;

Смотри также