Web3: Cookie сессии и защита запросов
Оглавление курса «Web3: вход, смарт-аккаунты и индексатор» · Урок 7 из 30.
После правильного входа браузер получает обычную серверную сессию. Подпись кошелька не должна становиться постоянным bearer-токеном, который отправляется при каждом действии. В этом уроке определим cookie сессии, её срок и защиту изменяющих запросов. Результат — кабинет читателя использует привычную веб-модель, а одноразовое сообщение остаётся только этапом аутентификации.
Предполагается успешный маршрут проверки SIWE и атомарное потребление challenge. Сервер, cookie и HTTP-программы не запускались. Домен library.example используется для объяснения; реальные настройки HTTPS и reverse proxy требуют отдельного процесса развертывания. Базовый CourseCatalog и его publisher не меняются.
Идентификатор сессии
Сервер создаёт непредсказуемый идентификатор и сохраняет связанную запись: проверенный адрес, сеть входа, время создания, срок и состояние отзыва. Браузер получает только идентификатор в cookie. Адрес в открытом JSON-объекте не заменяет эту запись и не может сам объявить authenticated = true.
Для учебной модели идентификатор можно сформировать из случайных32 байтов. Хранилище определяет, как он индексируется и защищается. Часто сохраняют производный хеш идентификатора, чтобы утечка базы не давала готовый токен. Это отдельный инженерный выбор; наша статья не обещает полноценную инфраструктуру сессий по одной функции генерации.
Сессия создаётся после одноразового перехода challenge. Если её запись отказала, старый nonce не возвращается в свободное состояние автоматически. Пользователь получает новую попытку входа. Для согласованной базы эти действия могут находиться в одной транзакции, чтобы избежать потерянного промежутка. Семантика восстановления определяется явно.
Cookie и её границы
Ниже пример HTTP-заголовка для сервиса, работающего через HTTPS. Значение SESSION_ID является обозначением генерируемого идентификатора, а не настоящим токеном.
Set-Cookie: __Host-library_session=SESSION_ID; Path=/; Secure; HttpOnly; SameSite=Lax
Префикс __Host- требует соответствующих условий поддерживающего браузера: Secure, Path=/ и отсутствие Domain. Это помогает ограничить cookie конкретным host. Он не заменяет проверку сервера и не является универсальной защитой от всех атак. На локальном HTTP-окружении политика Secure требует отдельной настройки или локального HTTPS, а не молчаливого отключения production-флагов.
HttpOnly запрещает обычному JavaScript страницы читать cookie. Это уменьшает прямое раскрытие идентификатора при некоторых сценариях внедрения кода, но не делает XSS безвредным: чужой скрипт может всё ещё выполнять запросы от имени браузера. Поэтому безопасный DOM, ограничения сторонних скриптов и проверка действий остаются важными.
SameSite=Lax ограничивает часть межсайтовых отправок cookie. Но это не исчерпывающая защита изменяющих операций. Особенно нельзя реализовывать изменение прогресса через GET и ожидать, что один флаг всё решит. Серверная политика origin и CSRF рассматривается совместно с маршрутом запроса.
Защита изменения прогресса
Публичный курс17 доступен через GET без сессии. Сохранение персонального прогресса использует POST или другой подходящий изменяющий метод. Сервер проверяет сессию, допустимый Origin и CSRF-механизм выбранной архитектуры. Адрес аккаунта из тела запроса не выбирает пользователя: он определяется сессией.
CSRF-токен связывается с сессией и проверяется сервером по известному правилу. Его значение может быть доступно странице для отправки, но оно не размещается в URL и не подменяется простым hasWallet = true. Подпись SIWE защищает вход, а CSRF защищает использование веб-сессии в последующих запросах. Это разные этапы и разные угрозы.
Наивная проверка Origin.endsWith('library.example') неправильна. Она может принять незапланированное имя и не учитывает корректное представление origin. Сервер сопоставляет разобранный origin с известным списком, включая схему и порт. Политика proxy и публичного адреса сервиса сохраняется в конфигурации.
Срок и продление
Сессия имеет собственный срок, который не обязан совпадать с пятиминутным challenge. Короткий challenge ограничивает окно подписи, а срок кабинета относится к использованию уже созданной записи. Эти значения выбираются по задачам сервиса. Не следует считать любой удобный долгий срок универсальным правилом безопасности.
Продление сессии может зависеть от активности и повторной проверки для чувствительных действий. Сервер ограничивает абсолютный срок и возможность отзыва. Браузер не может продлить запись, просто изменив собственные часы или поле expiry в JSON. Cookie сообщает идентификатор, а действительность решает серверное хранилище.
Для контрактного аккаунта изменение правил подписи может потребовать пересмотра сессии. Сервис заранее определяет, какие действия требуют свежего подтверждения. Сам ERC-1271 не предоставляет готовую систему уведомлений обо всех возможных изменениях владельцев. Приложение не обещает автоматический отзыв без соответствующей интеграции.
Ответ браузеру
После входа сервер возвращает минимум нужных данных кабинета: проверенный адрес и возможности интерфейса. Эти возможности удобны для отображения, но каждый защищённый endpoint повторно проверяет авторизацию. Скрытая кнопка не является серверной защитой, как и в случае прав publisher в контракте.
Персональный ответ не должен попадать в публичный общий кеш сайта. Статические материалы ProfessorWeb могут кешироваться широко, а кабинет имеет другую политику. Смешение двух типов ответа иногда приводит к показу чужого прогресса через CDN. Заголовки кеширования и ключи запросов учитывают персональное происхождение данных.
Ожидаемые случаи
Правильная сессия позволяет сохранить прогресс собственного читателя. Истёкшая или отозванная запись требует нового входа. Чужой адрес в теле запроса не переназначает владельца данных. Межсайтовый изменяющий запрос не проходит политику origin и CSRF. Это критерии будущей проверки, которая здесь не выполнялась.
Для упражнения разделите данные публичной статьи, cookie-идентификатор, серверную запись и CSRF-токен. Объясните, какой элемент проверяется на каком этапе. Ожидаемый итог — подпись кошелька встроена в обычную защищённую веб-сессию без превращения её в постоянный пароль. Cookie описаны в MDN Set-Cookie, рекомендации сессий — в OWASP Session Management.
Отдельная cookie потока
До создания сессии сервер может использовать краткоживущую cookie потока входа. Она имеет другое назначение и не даёт доступа к прогрессу. После успеха её очищают или заменяют по политике. Нельзя считать наличие flowcookie признаком аутентифицированного пользователя: это лишь связь challenge с браузерной попыткой.