PHP OAuth2: Зачем нужен параметр state при авторизации через Google и как он защищает от атак CSRF?
При реализации авторизации через Google с использованием протокола OAuth2 в PHP-приложениях параметр `state` играет критически важную роль в обеспечении безопасности. Разберём подробно, что это такое, зачем он нужен и как именно защищает от CSRF-атак.
## Что такое параметр state в OAuth2
Параметр `state` — это случайная строка (токен), которую ваше приложение генерирует перед перенаправлением пользователя на страницу авторизации Google. После того как пользователь успешно авторизуется, Google возвращает этот параметр обратно в redirect_uri вместе с кодом авторизации. Приложение сравнивает полученный `state` с тем, что было сохранено в сессии. Если они совпадают — запрос легитимен.
## Как работает CSRF-атака без параметра state
Представьте сценарий без использования `state`:
1. Злоумышленник инициирует OAuth2-поток авторизации на своей стороне.
2. Получает URL с кодом авторизации от Google, но не завершает процесс.
3. Подставляет этот URL жертве (через изображение, ссылку, iframe).
4. Браузер жертвы выполняет запрос к вашему приложению с кодом злоумышленника.
5. Приложение привязывает аккаунт Google злоумышленника к аккаунту жертвы.
Теперь злоумышленник может войти в аккаунт жертвы через свой Google-аккаунт.
## Реализация защиты через state в PHP
php
// Шаг 1: Генерация и сохранение state
session_start();
$state = bin2hex(random_bytes(16)); // криптографически стойкая случайная строка
$_SESSION[‘oauth2_state’] = $state;
// Шаг 2: Добавление state в URL авторизации
$authUrl = ‘https://accounts.google.com/o/oauth2/auth?’ . http_build_query([
‘client_id’ => CLIENT_ID,
‘redirect_uri’ => REDIRECT_URI,
‘response_type’ => ‘code’,
‘scope’ => ‘openid email profile’,
‘state’ => $state,
]);
header(‘Location: ‘ . $authUrl);
// Шаг 3: Проверка state в callback
session_start();
if (!isset($_GET[‘state’]) || $_GET[‘state’] !== $_SESSION[‘oauth2_state’]) {
die(‘Ошибка: недействительный state. Возможная CSRF-атака.’);
}
unset($_SESSION[‘oauth2_state’]); // одноразовое использование
// Продолжаем обмен кода на токен…
## Требования к параметру state
— **Случайность**: используйте `random_bytes()` или `openssl_random_pseudo_bytes()`, не `rand()` или `mt_rand()`.
— **Достаточная длина**: минимум 16 байт (32 символа в hex).
— **Одноразовость**: после проверки удаляйте из сессии.
— **Привязка к сессии**: храните в `$_SESSION`, а не в cookie без httpOnly.
## Дополнительные возможности параметра state
Помимо защиты от CSRF, `state` можно использовать для передачи дополнительной информации: URL для редиректа после авторизации, идентификатор страницы, с которой начался процесс входа. Для этого кодируют JSON-строку в base64 и включают в `state` вместе с nonce.
## Итог
Параметр `state` — обязательный элемент безопасной реализации OAuth2. Без него ваше приложение уязвимо к атакам CSRF, которые могут привести к захвату аккаунтов пользователей. Всегда генерируйте криптографически стойкий `state`, сохраняйте его в сессии и проверяйте при каждом callback-запросе.
