Как правильно пробросить id_token от Apple OAuth в PHP-сессию, чтобы избежать перехвата через session_fixation?
При интеграции Sign in with Apple важно не только корректно обработать id_token, но и надёжно защитить PHP-сессию от атаки session fixation. Рассмотрим пошаговый подход.
## 1. Что такое session fixation и почему это важно
Session fixation — атака, при которой злоумышленник навязывает жертве заранее известный session ID. Если после аутентификации вы не пересоздаёте сессию, атакующий может получить доступ к авторизованной сессии пользователя.
## 2. Верификация id_token на стороне сервера
Перед записью чего-либо в сессию обязательно верифицируйте id_token:
— Загрузите публичные ключи Apple с `https://appleid.apple.com/auth/keys`
— Проверьте подпись JWT с помощью библиотеки (например, `firebase/php-jwt`)
— Убедитесь, что `iss` равен `https://appleid.apple.com`, `aud` совпадает с вашим `client_id`, а `exp` не истёк
— Проверьте `nonce` — он должен совпадать с тем, что вы отправили в запросе авторизации (защита от replay-атак)
php
$decoded = JWT::decode($idToken, JWK::parseKeySet($appleKeys), [‘RS256’]);
if ($decoded->iss !== ‘https://appleid.apple.com’) { /* ошибка */ }
if ($decoded->aud !== YOUR_CLIENT_ID) { /* ошибка */ }
if ($decoded->nonce !== $_SESSION[‘oauth_nonce’]) { /* ошибка */ }
## 3. Пересоздание сессии после аутентификации
Ключевой шаг против session fixation — вызов `session_regenerate_id(true)` сразу после успешной проверки токена:
php
session_start();
// … верификация id_token …
session_regenerate_id(true); // true — удаляет старый файл сессии
$_SESSION[‘user_id’] = $decoded->sub;
$_SESSION[’email’] = $decoded->email ?? null;
unset($_SESSION[‘oauth_nonce’]); // очищаем одноразовый nonce
Параметр `true` критически важен: он удаляет старую сессию с диска, не оставляя злоумышленнику возможности воспользоваться старым ID.
## 4. Дополнительные меры безопасности
— **Не храните сам id_token в сессии** — он содержит чувствительные данные и имеет ограниченный срок жизни. Храните только нужные атрибуты пользователя (`sub`, `email`).
— **Используйте HTTPS** — без него любая защита сессий бессмысленна.
— **Настройте cookie-флаги**: `session.cookie_secure = 1`, `session.cookie_httponly = 1`, `session.cookie_samesite = Strict`.
— **Привязывайте сессию к User-Agent и IP** (опционально, но повышает безопасность).
— **Устанавливайте короткий TTL сессии** и обновляйте session ID при каждом повышении привилегий.
## 5. Хранение nonce
Перед редиректом на Apple генерируйте криптографически стойкий nonce и сохраняйте его в сессии:
php
$nonce = bin2hex(random_bytes(16));
$_SESSION[‘oauth_nonce’] = $nonce;
// передайте хэш nonce в запрос к Apple: hash(‘sha256’, $nonce)
Apple возвращает хэш nonce в id_token, что позволяет связать запрос с ответом и исключить CSRF.
Следуя этим шагам, вы обеспечите безопасную передачу данных Apple OAuth в PHP-сессию и надёжно защититесь от session fixation.
