Практическое руководство по защите от CSRF в 2026 году с проверенными приёмами: SameSite, CSRF-токены, double submit и подходы для API. Пошаговые инструкции, команды проверки и примеры кода для реальных приложений.
0
Статья была полезной?
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…
Что такое CSRF в 2026?
Cross-Site Request Forgery (CSRF) остаётся уязвимостью на 2026 год: браузеры и серверы изменили поведение cookie и политики, но злоумышленники всё ещё используют подставные запросы для переводов денег, смен паролей и изменения настроек. За три года — с 2023 по 2026 — главные изменения: браузеры по умолчанию требовали явных SameSite атрибутов, а распространение SPA и мобильных приложений сместило акценты с cookie на токены.
Шаг 1: SameSite cookies
SameSite — самый недорогой и востребованный механизм по умолчанию. В 2025 и 2026 годах основные браузеры (Chrome, Firefox, Edge, Safari) интерпретируют cookie без явного атрибута как SameSite=Lax, что блокирует отправку cookie при кросс-сайтовых POST-запросах, но оставляет GET-запросы навигации. Для безопасных операций рекомендуется использовать комбинации: SameSite=Strict или SameSite=Lax для сессионных cookies и SameSite=None; Secure для кросс-доменных интеграций.
Практическая инструкция:
Для пользовательской сессии используйте: Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=2592000 (30 дней = 2 592 000 секунд). Это блокирует отправку cookie при автоматических POST-запросах с других сайтов, но допускает переходы по ссылкам.
Если есть интеграции через iframe или внешние платежи, используйте: Set-Cookie: token=xyz; HttpOnly; Secure; SameSite=None; Max-Age=86400. Обратите внимание: SameSite=None требует Secure (TLS) и не работает по HTTP. Браузеры после 2021 блокируют None без Secure.
Проверка на сервере: добавьте заголовок ответа с примером cookie и тестируйте на средах с разными браузерами. Тестовый набор: Chrome 120+ (2026-03), Firefox 117+ (2026-02), Safari 17+ (2026-01).
# Пример установки cookie в Node.js (Express)
res.cookie('session_id', sessionId, {
httpOnly: true,
secure: true, // обязательно для SameSite=None
sameSite: 'lax', // 'strict' | 'lax' | 'none'
maxAge: 2592000000 // 30 дней в миллисекундах
});
Если у вас старые клиенты (IE11 или встроенные WebView 2019-2020), добавьте проверку user-agent и не выставляйте SameSite=None для них, либо примените серверную стратегию обхода. В 2026 г. количество таких клиентов обычно < 2% для коммерческих проектов; для B2B-систем с корпоративными WebView затраты на поддержку достигают 1 200–2 500 рублей в час для специалистов при аудите совместимости.
Пример заголовка Set-Cookie с SameSite
Как эскалировать и тестировать
Для проверки быстро используйте curl и headless-браузер. Пример curl для проверки SameSite:
curl -I -k https://example.com/login
# см. Set-Cookie в заголовке
Автоматические тесты: в CI запускайте 3 сценария (Chrome, Firefox, Safari) через Playwright или Puppeteer. Рекомендация 2026: 3 теста на час при релизе фичи авторизации; время выполнения теста ~45–60 секунд, стоимость в CI около $0.02 за запуск на GitHub Actions.
Шаг 2: CSRF tokens
CSRF-токены остаются золотым стандартом для защиты state-changing операций на сервере. В 2026 году практикуют двухуровневый подход: SameSite для большинства операций и CSRF-токены для форм, AJAX POST/PUT/DELETE, где SameSite не покрывает бизнес-требования.
Как генерировать и валидировать:
Генерация: криптографически стойкий токен 32 байта (256 бит), Base64 или hex. Генерация в 2026: use system-provided CSPRNG. Пример: Node.js crypto.randomBytes(32).toString('hex'), PHP random_bytes(32).
Хранение: привязка к сессии на сервере (Redis, memcached или БД). Для Redis учтите: 1 токен = 64 байта, при 10 000 активных сессий — ~640 КБ + накладные расходы. Учитывайте TTL 24 часа или одно использование.
Включение в форму или заголовок: для HTML-форм добавляйте скрытый input; для AJAX — отдайте токен в meta-теге или отдельном endpoint и отправляйте через заголовок X-CSRF-Token или в теле JSON.
<!-- HTML форма -->
<input type="hidden" name="csrf_token" value="{{csrf_token}}">
<button>Отправить</button>
// AJAX: получить токен и отправить
fetch('/csrf-token').then(r => r.json()).then(data => {
fetch('/api/transfer', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': data.token },
body: JSON.stringify({ amount: 1000 })
});
});
Практические рекомендации по срокам и повторному использованию: выдавайте токен на сессию с TTL 24 часа, поддерживайте одноразовую валидацию для операций критической важности (переводы, смена почты). Переиспользование токена допустимо для менее критичных операций в пределах 24 часов — это уменьшает нагрузку на Redis на ~30% для приложений с большим числом AJAX-запросов.
Схема обмена CSRF токенами между клиентом и сервером
Проверка и диагностика
Проверка валидности токена: всегда сравнивайте токен в постоянном времени (constant time compare) для защиты от тайминговых атак. В Node.js используйте crypto.timingSafeEqual. Добавьте логи при неудачных валидациях: минимум 5 полей — IP, user-agent, route, time, reason; храните последние 100 записей на пользователя в логах безопасности.
Шаг 3: double submit
Double submit cookie — альтернативный метод, когда сервер не хранит token в сессии. Идея: сервер выдает CSRF-токен и дублирует его в cookie (HttpOnly=false). Клиент отправляет токен в заголовке или теле, а сервер сравнивает значение из cookie и из заголовка. Подходит для stateless-приложений и микросервисов.
Плюсы и минусы к 2026 году: плюс — отсутствие необходимости хранить токен в сессии (экономия RAM и запросов к Redis). Минус — cookie должно быть доступно в JS (HttpOnly=false), что повышает риск XSS. Следовательно, сочетайте double submit с жёсткими CSP и регулярным сканированием XSS. Для приложений с низким уровнем XSS-риска и высокой нагрузкой (1000+ req/s) double submit снижает расходы на Redis на 40–70%.
CSP: default-src 'self'; script-src 'self' (и nonce для динамических скриптов).
Логирование неудачных сравнений и частая ротация токенов.
Шаг 4: Защита CORS и заголовков
К 2026 году CORS — обычная точка контроля. CSRF-атака полагается на браузер, автоматически отправляющий cookie. Принудительная проверка CORS-заголовков и блокировка неблагонадёжных источников снижают вероятность успешной эксплуатации.
Рекомендации:
Запрещайте универсальный Access-Control-Allow-Origin: * для эндпоинтов, которые требуют cookie или авторизации. Вместо этого используйте белый список доменов и точечное перечисление.
Не разрешайте кросс-доменные credentials без строгой проверки: Access-Control-Allow-Credentials: true только при совпадении с разрешённым origin. Многие ошибки 2024–2025 были вызваны некорректной настройкой этой пары заголовков.
Делайте preflight caching: Access-Control-Max-Age: 86400 (1 день) чтобы снизить нагрузку при разрешённых origins.
# Пример настройки Nginx для CORS
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, X-CSRF-Token, Authorization' always;
if ($request_method = 'OPTIONS') {
return 204;
}
Тестирование: используйте curl с заголовком Origin и проверяйте ответы. Пример: curl -H "Origin: https://evil.com" -I https://api.example.com/secure — ответ не должен содержать допускающий credentials заголовок для неизвестного origin.
Шаг 5: Логирование и мониторинг
Защитные механизмы работают лучше, если виден результат. В 2026 году специалисты применяют три уровня логирования: application, security и infra. Для CSRF-дашборда полезны метрики: число неудачных валидаций CSRF-токенов в минуту, распределение по IP и user-agent, spike detection.
Практика по настройке:
Сбор: отправляйте события в central logging (ELK/Opensearch, Grafana Loki). Одно событие = ~1 KB. При 10 000 срабатываний в день — 10 MB/день.
Алертинг: настройте порог 50 неудачных CSRF-валидаций в 1 минуту по одному endpoint — сигнал к блокировке IP-диапазона или WAF-правилу. В 2025 этот порог доказал свою эффективность на проектах с 2–5 миллионов пользователей.
RCA: собирайте первичные данные (трассировки, request headers) для разбора инцидента. Храните 14 дней детальных логов и 90 дней агрегированных.
Какие типичные дыры?
Типичные ошибки на 2025–2026 годы, которые я встречал при аудитах (реальные кейсы):
Отсутствие SameSite для сессионных cookies — часто встречалось в 2022–2024, к 2026 это редкость, но в старых монолитах бывает. Решение: единообразная middleware-правка в кодовой базе.
CSRF-токен помещён в localStorage и не отправляется автоматически — разработчики думали, что это активно защищает, но забыли обеспечить передачу токена для всех типов запросов. Решение: отдавать токен в meta-теге или cookie и централизовать логику отправки в клиентской библиотеке.
Double submit с HttpOnly=true cookie — ошибка: риск XSRF остаётся, потому что cookie недоступно для сравнения. Решение: cookie для double submit должно быть доступно JS (HttpOnly=false), но компенсируйте жёстким CSP и XSS-scan.
Неправильная настройка CORS: Access-Control-Allow-Origin: * вместе с Access-Control-Allow-Credentials: true. Это даёт злоумышленнику возможность выполнять запросы с cookie. Решение: фиксируйте origin серверно и возвращайте конкретный origin в заголовке.
Отсутствие постоянного сравнения времени (timing-safe compare) при валидации токенов — риск побочных атак. Решение: используйте встроенные методы для constant-time сравнения.
Частая реальная ошибка: команда думает, что SameSite=None + Secure решит все проблемы с CSRF при интеграциях — но это не защищает от XSS и не покрывает API без cookie.
Что с API?
API и CSRF — особая тема. Если ваш API использует cookie-based авторизацию, то оно подвержено CSRF. Если используется токен в Authorization: Bearer, то классическая CSRF-атака не работает, потому что браузер не добавляет Authorization автоматически. Переход на token-based auth — лучшее решение для публичных API в 2026 году.
Рекомендации для API:
Для веб-форм и веб-приложений: оставьте cookie для удобства, но комбинируйте с CSRF-токеном и SameSite.
Для REST/GraphQL API от внешних клиентов: используйте Authorization: Bearer. Токены в localStorage или secure store мобильного приложения — допустимы при защите от XSS. Ротация токенов: access token 15 минут, refresh token 7–30 дней.
Для смешанных сценариев (браузер + API): применяйте custom header (например, X-Requested-With) и проверяйте его на сервере; однако помните, что заголовки могут быть подделаны на стороне клиента, поэтому это не полноценная защита без token-проверки.
# Пример проверки на сервере: предпочитать Authorization
if (req.headers.authorization) {
// обрабатывать Bearer токен
} else {
// проверять cookie + CSRF
}
Практическая заметка: мобильные SDK в 2025–2026 годах чаще используют OAuth2/OIDC. Настройка PKCE обязательна для публичных клиентов. Если вы используете JWT, добавьте проверку jti и отзыва (revocation list) для критичных операций; хранение списка отозванных jti в Redis на 30 дней при среднем трафике 1000 токенов/день добавляет ~10–50 MB хранилища.
Частые вопросы
как SameSite влияет на POST запросы?
SameSite=Lax блокирует отправку cookie при кросс-сайтовых запросах, которые инициируются скриптами (например, кросс-сайтовые POST). GET-запросы навигации обычно допускаются при Lax. SameSite=Strict запрещает отправку cookie даже при навигации с другого сайта. SameSite=None позволяет отправку cookie для кросс-доменных запросов, но требует Secure. В 2026 по умолчанию cookie без атрибута трактуются как Lax в большинстве браузеров, поэтому POST-запросы из внешних форм не будут содержать cookie при Lax, что уменьшает риск CSRF для POST-эндпоинтов.
что лучше: CSRF token или double submit?
Выбор зависит от требований: CSRF token (сервер-сторедж) безопаснее против XSS, так как token может быть HttpOnly и недоступен JS, но требует хранения на сервере (Redis/DB) и управления TTL. Double submit экономит серверные ресурсы и подходит для stateless-архитектур, но требует доступа cookie в JS (HttpOnly=false) и, следовательно, повышает требование к защите от XSS. Для критичных операций (платежи) рекомендуют server-side token; для масштабируемых API — double submit в сочетании с анти-XSSмирами.
почему Authorization: Bearer защищает от CSRF?
CSRF использует браузерную автоматическую отправку cookie. Заголовок Authorization: Bearer не добавляется браузером автоматически; он должен быть явным в коде клиента. Злоумышленнику на чужом сайте нельзя заставить браузер отправить корректный Authorization-заголовок, если у него нет токена. Поэтому перевод API на bearer-токены значительно снижает риск CSRF. Однако это не защищает от компрометации токена (XSS, утекший токен), поэтому нужен комплекс мер (short-lived tokens, refresh, PKCE для публичных клиентов).
где проверять CSRF токен: middleware или в контроллере?
Лучше в middleware/фильтре HTTP-уровня, чтобы централизовать логику и избежать пропусков в отдельных контроллерах. Middleware упрощает применение политики: например, исключить GET/HEAD/OPTIONS маршруты и требовать проверку для POST/PUT/DELETE/PATCH. В Node.js/Express это middleware с приоритетом до маршрутизации. В Java/Spring аналогично — фильтры в цепочке сервлетов. Централизация снижает риск человеческой ошибки и упрощает аудит.
сколько стоит внедрить CSRF-защиту в среднем?
Стоимость зависит от масштаба проекта. Для среднего проекта (веб-приложение с 50 экранов, 10 API-эндпоинтов) оценка 2026: аудит и внедрение SameSite, CSRF-токенов, CI-тестов и WAF правил — 40–80 инженерных часов. При ставке 4 000–8 000 рублей/час это 160 000–640 000 рублей. Для больших проектов (микросервисы, мобильные клиенты) — 200–800 часов. Основные затраты идут на тестирование совместимости и обновление клиентов (особенно мобильных и legacy WebView).
Дополнительно: подключение систем логирования и алертинга — 20–60 часов, настройка Playwright тестов — 8–24 часов. Экономия риска: предотвращённые инциденты с финансовыми потерями зачастую окупают внедрение в первые 6–12 месяцев.
Если хотите — могу подготовить чек-лист правок для вашего кода и конфигурации Nginx/Express/Apache, провести быструю ревизию и указать приоритеты фиксов по времени и стоимости.
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…