Надежная защита от CSRF атак: токены, Same-Site Cookie и другие методы
Перейти

Надежная защита от CSRF атак: токены, Same-Site Cookie и другие методы

#Веб-разработка  #Безопасность (XSS/CSRF)  #Веб-безопасность  
Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Разработчики программного обеспечения, заинтересованные в безопасности веб-приложений
  • Специалисты по информационной безопасности и системным администраторам
  • Руководители IT-отделов, ответственные за внедрение мер по защите данных и информации в компаниях

CSRF-атаки — как тихие воры, проникающие в дом через открытую форточку: вы их не замечаете, пока не обнаружите пропажу. Одна успешная атака может стоить бизнесу миллионы, а пользователям — личные данные и деньги. В 2022 году количество CSRF-уязвимостей выросло на 23%, а средний ущерб от одного инцидента составил $58,000. В этой статье я расскажу, как создать непроницаемую защиту от CSRF-атак с помощью токенов, Same-Site Cookie и других методов. Вы получите готовые решения, примеры кода и стратегии защиты, которые можно внедрить уже сегодня. 🔒

Что такое CSRF-атаки и почему они опасны

Cross-Site Request Forgery (CSRF или XSRF) — это тип атаки, при которой злоумышленник заставляет аутентифицированного пользователя выполнить нежелательное действие на веб-сайте, где тот уже авторизован. Представьте: вы авторизовались в своем интернет-банке и, не выходя из аккаунта, перешли на другой сайт, содержащий вредоносный код. Этот код может отправить запрос в ваш банк от вашего имени — например, на перевод средств.

Алексей Петров, руководитель отдела ИБ

В 2021 году мы столкнулись с атакой на корпоративный портал, где из-за отсутствия защиты от CSRF злоумышленники смогли изменить платежные реквизиты для 12 поставщиков. Система считала запросы легитимными, поскольку они выполнялись от имени авторизованного финансового директора, который случайно перешел по вредоносной ссылке. Прежде чем мы обнаружили проблему, компания потеряла более 2 миллионов рублей. После этого инцидента мы внедрили многоуровневую защиту с CSRF-токенами и Same-Site Cookie, что полностью предотвратило повторение ситуации.

CSRF-атаки особенно опасны по нескольким причинам:

  • Незаметность: пользователи обычно не подозревают, что стали жертвами атаки
  • Высокая эффективность: злоумышленнику не нужно перехватывать трафик или получать доступ к учетным данным
  • Широкий спектр последствий: от изменения настроек аккаунта до финансовых операций и кражи данных
  • Сложность обнаружения: атаки часто остаются незамеченными до наступления серьезных последствий

Типичная CSRF-атака работает следующим образом:

  1. Пользователь авторизуется на легитимном сайте (например, банк)
  2. Сессия пользователя остается активной через cookies
  3. Злоумышленник создает вредоносную страницу с автоматически выполняющимся запросом к легитимному сайту
  4. Пользователь каким-то образом попадает на вредоносную страницу
  5. Браузер пользователя автоматически отправляет запрос к легитимному сайту вместе с cookies сессии
  6. Легитимный сайт выполняет запрос, считая его действительным

Наиболее уязвимыми для CSRF-атак являются действия, изменяющие состояние на сервере:

Тип действия Пример уязвимости Потенциальный ущерб
Финансовые операции Перевод средств, изменение платежных реквизитов Прямые финансовые потери
Управление учетными данными Смена пароля, email Потеря контроля над аккаунтом
Административные действия Добавление/удаление пользователей, изменение прав Компрометация системы
Публикация контента Размещение постов, комментариев от имени пользователя Репутационный ущерб
Пошаговый план для смены профессии

Защита через CSRF-токены и их реализация

CSRF-токены — наиболее распространенный и эффективный метод защиты от атак межсайтовой подделки запросов. Принцип действия основан на проверке уникального, непредсказуемого значения (токена), которое генерируется на сервере и должно быть включено в каждый запрос, изменяющий данные. 🛡️

Механизм работы CSRF-токенов:

  1. Сервер генерирует уникальный токен для каждой сессии пользователя
  2. Токен передается клиенту при загрузке страницы (обычно в HTML-форме)
  3. Клиент отправляет токен обратно серверу при каждом запросе, изменяющем состояние
  4. Сервер проверяет соответствие полученного токена тому, что был выдан клиенту
  5. Запрос выполняется только при совпадении токенов

Поскольку злоумышленник не может прочитать токен из-за политики Same-Origin, он не может сформировать корректный запрос с действительным токеном.

Рассмотрим примеры реализации CSRF-защиты в различных технологиях:

1. PHP реализация:

php
Скопировать код
// Генерация CSRF-токена
function generateCSRFToken() {
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}

// В HTML-форме
echo '<form method="post" action="process.php">';
echo '<input type="hidden" name="csrf_token" value="'.generateCSRFToken().'">';
echo '<!-- другие поля формы -->';
echo '</form>';

// Проверка токена при обработке запроса
function validateCSRFToken($token) {
if (!isset($_SESSION['csrf_token']) || $token !== $_SESSION['csrf_token']) {
die('CSRF token validation failed');
}
}

// В обработчике
validateCSRFToken($_POST['csrf_token']);
// Продолжение обработки запроса при валидном токене

2. Node.js (Express) реализация:

JS
Скопировать код
// Установка пакета
// npm install csurf

const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

// Применение к маршрутам
app.get('/form', csrfProtection, (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});

app.post('/process', csrfProtection, (req, res) => {
// Токен проверяется автоматически middleware
// Если проверка не пройдена, будет выброшена ошибка
// Обработка формы при успешной валидации
});

// В шаблоне формы
// <input type="hidden" name="_csrf" value="<%= csrfToken %>">

3. Django (Python) реализация:

Python
Скопировать код
# Django имеет встроенную защиту от CSRF
# В settings.py уже включен middleware
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', # CSRF защита
# ...
]

# В шаблоне формы
# {% csrf_token %}

# В представлении проверка происходит автоматически
@require_POST
def my_view(request):
# Обработка только если CSRF-проверка пройдена
# ...

Ключевые аспекты правильной реализации CSRF-токенов:

  • Криптографическая стойкость: используйте криптостойкие генераторы случайных чисел
  • Привязка к сессии: токен должен быть связан с сессией конкретного пользователя
  • Одноразовость или ограниченный срок действия: для особо критичных операций генерируйте новый токен после каждого использования
  • Проверка на серверной стороне: никогда не полагайтесь на клиентскую валидацию
  • Отказоустойчивость: корректно обрабатывайте ситуации с невалидным токеном

Same-Site Cookie: настройка и эффективность

Same-Site Cookie — мощный инструмент защиты от CSRF-атак, встроенный непосредственно в механизм работы браузера. Эта директива определяет, будут ли cookie отправляться вместе с кросс-сайтовыми запросами, что позволяет значительно снизить риск CSRF-атак. 🍪

Директива SameSite имеет три возможных значения:

  • Strict: cookie отправляются только при переходе с того же домена
  • Lax: cookie отправляются при переходе с другого домена, но только для GET-запросов верхнего уровня
  • None: cookie отправляются со всеми кросс-сайтовыми запросами (требует Secure флага)

С 2020 года большинство современных браузеров установили SameSite=Lax как значение по умолчанию, что уже обеспечивает базовый уровень защиты от CSRF.

Значение SameSite Запросы того же сайта Переход по ссылке <form> GET <form> POST AJAX/fetch <img> и др. ресурсы
Strict
Lax
None (с Secure)

Настройка Same-Site Cookie в различных технологиях:

1. PHP:

php
Скопировать код
// PHP 7.3+ поддерживает SameSite
setcookie(
'session_id',
$sessionId,
[
'expires' => time() + 86400,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict' // 'Lax' или 'None'
]
);

// Для PHP < 7.3
setcookie(
'session_id',
$sessionId,
time() + 86400,
'/; samesite=Strict',
'example.com',
true,
true
);

2. Node.js (Express):

JS
Скопировать код
// Использование cookie-parser
app.use(cookieParser());

// Установка cookie
res.cookie('session_id', sessionId, {
maxAge: 86400000,
httpOnly: true,
secure: true,
sameSite: 'strict' // 'lax' или 'none'
});

// Или с использованием express-session
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: true,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'strict'
}
}));

3. Python (Django):

Python
Скопировать код
# В settings.py
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Strict' # 'Lax' или 'None'

CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = 'Strict'

Ирина Соколова, DevOps-инженер

Внедрение Same-Site Cookie стало переломным моментом в защите нашего маркетплейса. До этого мы использовали только CSRF-токены, но периодически сталкивались с атаками, когда злоумышленники находили обходные пути. Особенно проблемной была API-точка изменения адреса доставки, которая иногда обрабатывалась без должной проверки токена.

После масштабного инцидента, когда были перенаправлены заказы на сумму около 300,000 рублей, мы решили внедрить многослойную защиту. Установили Same-Site=Strict для всех аутентификационных cookie и переработали API. Результаты превзошли ожидания: количество попыток CSRF-атак, регистрируемых нашими системами мониторинга, сократилось на 94%, а оставшиеся 6% успешно блокировались другими уровнями защиты. Главный урок, который я извлекла: никогда не полагайтесь на единственный механизм защиты, особенно для критичных операций.

При выборе значения SameSite следует учитывать баланс между безопасностью и удобством использования:

  • Strict: максимальная защита, но может ухудшить UX (например, при переходе по ссылкам из email)
  • Lax: разумный компромисс для большинства приложений, достаточный уровень защиты при сохранении базовой функциональности
  • None: используйте только при необходимости кросс-доменного взаимодействия, и обязательно с флагом Secure

Важные моменты при использовании Same-Site Cookie:

  • Не все браузеры одинаково поддерживают SameSite, особенно старые версии
  • Директива не работает для HTTP-соединений с SameSite=None (требуется HTTPS)
  • Same-Site Cookie не заменяет другие методы защиты, а дополняет их
  • Для API, которые должны принимать кросс-сайтовые запросы, используйте другие механизмы авторизации (например, токены в заголовках)

Двухфакторная аутентификация против CSRF

Двухфакторная аутентификация (2FA) — это не прямой метод защиты от CSRF, но дополнительный уровень безопасности, значительно снижающий риск успешной атаки для критически важных операций. 2FA работает по принципу "что-то, что вы знаете (пароль) + что-то, что у вас есть (устройство)" и требует подтверждения действий через второй канал. 📱

2FA как защитный механизм против CSRF особенно эффективна для следующих операций:

  • Финансовые транзакции: переводы средств, изменение платежных реквизитов
  • Изменение критических настроек аккаунта: пароля, email, телефона
  • Административные действия: управление пользователями, изменение прав доступа
  • Доступ к конфиденциальным данным: медицинская информация, личные документы

Преимущества 2FA в контексте CSRF-защиты:

  1. Даже если злоумышленник заставит браузер выполнить подделанный запрос, операция не будет завершена без подтверждения по второму фактору
  2. 2FA не зависит от механизма работы cookie и Same-Origin Policy, что делает её более устойчивой к новым типам атак
  3. Пользователь осознанно подтверждает операцию, что снижает риск социальной инженерии

Распространенные методы реализации 2FA:

  • SMS-коды: простое внедрение, но уязвимо к перехвату SMS
  • Приложения-аутентификаторы (Google Authenticator, Authy): генерация временных одноразовых кодов (TOTP)
  • Аппаратные ключи (YubiKey, FIDO U2F): наиболее безопасный вариант, устойчивый к фишингу
  • Биометрия: отпечатки пальцев, распознавание лица (требует поддержки устройством)
  • Пуш-уведомления в мобильных приложениях: удобно для пользователей, высокая безопасность

Пример интеграции 2FA (на примере PHP с использованием TOTP):

php
Скопировать код
// Установка библиотеки
// composer require spomky-labs/otphp

use OTPHP\TOTP;

// Генерация секретного ключа для пользователя при настройке 2FA
function setupUserTOTP($userId) {
$totp = TOTP::create();
$secret = $totp->getSecret();

// Сохраняем секрет в базе данных для пользователя
saveUserTOTPSecret($userId, $secret);

// Генерируем QR-код для настройки приложения пользователем
$qrCodeUrl = $totp->getProvisioningUri('user@example.com', 'MyApp');

return [
'secret' => $secret, 
'qrCodeUrl' => $qrCodeUrl
];
}

// Проверка кода для критической операции
function verifyTOTPForOperation($userId, $inputCode) {
// Получаем секрет пользователя из БД
$secret = getUserTOTPSecret($userId);

$totp = TOTP::create($secret);

// Проверяем код
return $totp->verify($inputCode);
}

// В обработчике критической операции
if (isset($_POST['operation']) && $_POST['operation'] == 'transfer_money') {
// Сначала проверяем CSRF-токен
validateCSRFToken($_POST['csrf_token']);

// Затем проверяем 2FA код
if (!verifyTOTPForOperation($_SESSION['user_id'], $_POST['totp_code'])) {
die('Invalid 2FA code');
}

// Код выполнения операции при успешной проверке
performMoneyTransfer();
}

Лучшие практики при внедрении 2FA для защиты от CSRF:

  • Комбинируйте с другими методами: 2FA должна дополнять, а не заменять CSRF-токены и Same-Site Cookie
  • Выборочное применение: требуйте 2FA только для критичных операций, чтобы не ухудшать пользовательский опыт
  • Проверка на стороне сервера: никогда не полагайтесь на клиентскую валидацию 2FA
  • Ограничение попыток: внедрите защиту от перебора для предотвращения атак методом "грубой силы"
  • Резервные методы: предоставьте пользователям запасной способ аутентификации в случае потери основного

Комплексный подход: комбинация методов защиты

Наиболее эффективная стратегия защиты от CSRF-атак — это многоуровневый подход, комбинирующий различные методы. Каждый метод имеет свои сильные стороны и ограничения, поэтому их комбинация создает "защиту в глубину", значительно повышающую безопасность приложения. 🛡️

Оптимальная комбинация защитных мер включает:

  • CSRF-токены: основной механизм защиты для всех форм и запросов, изменяющих данные
  • Same-Site Cookie: дополнительный барьер, блокирующий отправку cookie с кросс-сайтовыми запросами
  • Двухфакторная аутентификация: для критически важных операций
  • Проверка Referer/Origin: дополнительный слой проверки источника запроса
  • Выделение API: использование современных подходов к аутентификации для API (JWT, OAuth)

Ниже представлена матрица защитных мер в зависимости от типа операций:

Тип операции CSRF-токены SameSite Cookie 2FA Проверка Referer
Чтение данных (GET) Опционально Lax Не требуется Опционально
Базовые операции изменения Lax Не требуется
Важные изменения Strict Опционально
Критические операции Strict
API для внешних систем JWT/токены в заголовках None с защитой API-ключами OAuth с областями доступа CORS-политика

Рассмотрим практический пример реализации многоуровневой защиты для критической операции (перевод денег):

JS
Скопировать код
// Пример на Node.js (Express)

// 1. Настройка CSRF-защиты
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: { 
sameSite: 'strict',
secure: true,
httpOnly: true
}});

// 2. Настройка сессионных cookie с SameSite
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: true,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'strict'
}
}));

// 3. Middleware проверки Referer
function checkReferer(req, res, next) {
const referer = req.get('Referer');
const host = req.get('Host');

if (!referer || !referer.includes(host)) {
return res.status(403).send('Invalid referer');
}
next();
}

// 4. Middleware для проверки 2FA
function require2FA(req, res, next) {
if (!req.session.user) {
return res.status(401).send('Authentication required');
}

// Проверка наличия 2FA в запросе
if (!req.body.twoFactorCode) {
return res.status(403).send('2FA required for this operation');
}

// Валидация 2FA кода
if (!validateTOTP(req.session.user.id, req.body.twoFactorCode)) {
return res.status(403).send('Invalid 2FA code');
}

next();
}

// 5. Маршрут с многоуровневой защитой для критической операции
app.post(
'/api/transfer_money',
csrfProtection, // CSRF-защита
checkReferer, // Проверка Referer
require2FA, // Проверка 2FA
(req, res) => {
// Дополнительная бизнес-логика валидации
if (req.body.amount <= 0) {
return res.status(400).send('Invalid amount');
}

// Выполнение операции при успешном прохождении всех проверок
performMoneyTransfer(req.session.user.id, req.body.destination, req.body.amount)
.then(() => {
res.json({ success: true, message: 'Transfer completed' });
})
.catch(err => {
res.status(500).json({ success: false, error: err.message });
});
}
);

Дополнительные рекомендации для усиления защиты:

  1. Используйте новейшие стандарты:

    • Content Security Policy (CSP) для предотвращения XSS-атак
    • Строгие CORS-политики для API
    • HTTP-заголовки безопасности (X-Content-Type-Options, X-Frame-Options)
  2. Внедрите мониторинг безопасности:

    • Логирование попыток CSRF
    • Алерты при подозрительной активности
    • Периодическое тестирование на проникновение
  3. Обновляйте зависимости: регулярно проверяйте и обновляйте библиотеки для устранения известных уязвимостей

  4. Проводите обучение разработчиков: убедитесь, что все члены команды понимают принципы защиты от CSRF

Помните, что безопасность — это не конечная точка, а процесс. Регулярно пересматривайте и обновляйте стратегии защиты в соответствии с новыми угрозами и лучшими практиками.

Защита от CSRF-атак требует комплексного подхода, адаптированного к особенностям вашего приложения. Начните с базовых механизмов — CSRF-токенов и Same-Site Cookie. Добавьте двухфакторную аутентификацию для критичных операций. Помните: каждый дополнительный слой защиты снижает вероятность успешной атаки в разы. Современный ландшафт угроз постоянно меняется, поэтому регулярный аудит безопасности и следование новейшим стандартам — неотъемлемая часть защиты. Безопасное приложение сегодня — это не то, которое никогда не взломают, а то, которое способно эффективно противостоять максимальному количеству известных атак.

Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей
Что такое CSRF?
1 / 5

Элина Баранова

разработчик Android

Свежие материалы

Загрузка...