
JWT (JSON Web Token) используется для аутентификации пользователей и передачи данных между клиентом и сервером. Неправильное хранение токена повышает риск утечки данных и несанкционированного доступа. Например, токен в localStorage доступен через JavaScript, что делает его уязвимым к атакам XSS. Исследования показывают, что более 70% веб-приложений, использующих localStorage для токенов, сталкиваются с уязвимостями XSS.
Наиболее защищённый способ хранения JWT – HttpOnly cookies. Они недоступны через JavaScript, что снижает риск кражи токена при XSS. Для защиты от CSRF важно использовать флаг SameSite=Strict и включить Secure для передачи cookie только по HTTPS. Такие настройки предотвращают подделку запросов с других сайтов и ограничивают передачу токена.
Кратковременное хранение токена в sessionStorage может быть оправдано для приложений с минимальной длительностью сессии. В этом случае токен автоматически удаляется после закрытия вкладки, снижая риск длительного хранения компрометированных данных. Однако при выборе этого метода важно избегать повторного использования токена в разных вкладках и реализовать контроль времени жизни токена.
Для приложений с высокой чувствительностью данных можно хранить токен в памяти приложения. Такой подход исключает запись токена на диск, но требует корректного управления состоянием при обновлении токена и перезагрузке страницы. Любая перезагрузка сбрасывает токен, поэтому необходимо реализовать безопасный механизм обновления через защищённый endpoint.
Почему хранить JWT в localStorage может быть опасно

localStorage предоставляет постоянное хранилище на стороне клиента, доступное через JavaScript. Любой скрипт на странице может получить токен, что делает его уязвимым к XSS (Cross-Site Scripting). Согласно исследованиям, более 60% веб-приложений, использующих localStorage для хранения токенов, имеют XSS-уязвимости.
Основные угрозы при хранении JWT в localStorage:
- Доступ через JavaScript: сторонние скрипты или внедрённый вредоносный код могут прочитать токен.
- Долгоживущие токены: данные сохраняются после закрытия вкладки, увеличивая окно для потенциальных атак.
- Отсутствие защиты от CSRF: токен не привязан к конкретной сессии или домену, что позволяет использовать его в поддельных запросах, если XSS реализован.
- Сложности с контролем времени жизни: localStorage не удаляет токены автоматически по истечении срока действия, что требует дополнительной логики в приложении.
Рекомендации при использовании localStorage:
- Использовать короткоживущие access-токены и хранить refresh-токены в HttpOnly cookie.
- Внедрять строгую валидацию и очистку всех пользовательских данных, чтобы снизить риск XSS.
- Минимизировать использование сторонних скриптов, особенно тех, которые выполняют динамический код.
- Рассмотреть альтернативы: хранение токена в памяти приложения для кратковременных сессий или в HttpOnly cookie для долгосрочного хранения.
Использование HttpOnly cookies для защиты токена
HttpOnly cookies недоступны через JavaScript, что делает их безопасным инструментом для хранения JWT. Даже при успешной атаке XSS злоумышленник не сможет прочитать токен напрямую. Использование флага Secure обеспечивает передачу cookie только через HTTPS, предотвращая перехват данных в сетях с нешифрованным трафиком.
Для защиты от CSRF рекомендуется включать флаг SameSite=Strict или SameSite=Lax. Это ограничивает автоматическую отправку cookie при запросах с других доменов. В сочетании с коротким сроком жизни access-токена и refresh-токеном, хранящимся отдельно, такой подход снижает риск компрометации авторизации.
Практические рекомендации при работе с HttpOnly cookies:
- Разделять access и refresh токены: access хранить в HttpOnly cookie, refresh – в другом безопасном хранилище для обновления токена.
- Устанавливать короткий срок жизни токена: 5–15 минут для access-токена снижает потенциальный ущерб при компрометации.
- Обновлять токен через защищённый endpoint: сервер проверяет refresh-токен и выдает новый access-токен, минимизируя риск использования старого токена.
- Ограничивать доступ к cookie по домену и пути: это снижает вероятность утечки токена на других страницах сайта.
Сравнение sessionStorage и localStorage для кратковременных токенов

sessionStorage и localStorage предоставляют клиентское хранилище для JWT, но имеют ключевые различия, влияющие на безопасность и управление токенами. sessionStorage существует только в рамках одной вкладки и автоматически очищается после её закрытия, тогда как localStorage сохраняет данные до явного удаления.
Преимущества sessionStorage для кратковременных токенов:
- Автоматическое удаление при закрытии вкладки: снижает риск длительного хранения токена при XSS.
- Изоляция вкладок: токен одной вкладки недоступен в других вкладках браузера.
- Простота использования: не требуется дополнительная логика очистки токена по истечении сессии.
Недостатки sessionStorage по сравнению с localStorage:
- Нет долговременного хранения: при обновлении страницы или случайном закрытии вкладки токен теряется.
- Не подходит для многовкладочных приложений: токен нельзя использовать одновременно в нескольких вкладках.
Рекомендации по выбору хранилища:
- Использовать sessionStorage для короткоживущих access-токенов и операций в рамках одной вкладки.
- Для долгосрочных токенов или возможности работы в нескольких вкладках рассмотреть HttpOnly cookies с безопасными флагами.
- Не хранить refresh-токены в sessionStorage, так как их потеря приведёт к невозможности обновления access-токена без повторной аутентификации.
Хранение токена в памяти приложения: плюсы и минусы

Хранение JWT в оперативной памяти приложения исключает запись токена на диск, снижая риск его кражи при XSS или компрометации localStorage. Такой подход подходит для одностраничных приложений с кратковременной сессией и минимальной необходимостью перезагрузки страницы.
Преимущества хранения токена в памяти:
- Отсутствие долговременного хранилища: токен исчезает при закрытии страницы или вкладки, уменьшая окно для атак.
- Недоступность через сторонние скрипты: токен не сохраняется в localStorage или cookie, поэтому JavaScript на странице не может его прочитать без явного доступа приложения.
- Контроль обновления: можно реализовать безопасное обновление токена через защищённый endpoint, минимизируя риск использования устаревшего токена.
Недостатки хранения токена в памяти:
- Потеря токена при перезагрузке страницы: требует дополнительной логики для повторной аутентификации или безопасного обновления токена.
- Сложности с многовкладочной работой: каждая вкладка имеет отдельную копию токена, что усложняет синхронизацию состояния пользователя.
- Зависимость от состояния приложения: сбои или ошибки в приложении могут привести к непреднамеренной потере токена.
Рекомендации:
- Использовать этот метод для кратковременных access-токенов.
- Реализовать механизм безопасного обновления токена через серверный endpoint.
- При необходимости долговременного хранения комбинировать с HttpOnly cookies для refresh-токена.
Риски XSS и CSRF при хранении JWT

Хранение JWT в клиентском хранилище, доступном через JavaScript, делает токен уязвимым к XSS (Cross-Site Scripting). При успешной атаке злоумышленник может выполнить скрипт на странице и получить токен, используя его для несанкционированного доступа. CSRF (Cross-Site Request Forgery) возникает, когда атакующий инициирует запрос от имени пользователя, используя существующий токен без его ведома.
Ключевые угрозы XSS и CSRF при хранении JWT:
| Угроза | Описание | Пример |
|---|---|---|
| XSS | Внедрение вредоносного скрипта на страницу, который читает JWT из localStorage или sessionStorage | Злоумышленник вставляет скрипт через форму комментариев и перехватывает токен |
| CSRF | Инициирование нежелательного запроса от имени пользователя с автоматическим отправлением токена | Вредоносный сайт отправляет POST-запрос на API, используя действующий JWT в cookie |
Рекомендации для снижения рисков:
- Хранить access-токен в HttpOnly cookie, чтобы предотвратить доступ через JavaScript.
- Включать SameSite=Strict или SameSite=Lax для cookie, чтобы уменьшить вероятность CSRF.
- Применять Content Security Policy (CSP) для ограничения выполнения внешнего и inline-кода.
- Использовать короткоживущие токены и безопасные refresh-токены для минимизации ущерба при компрометации.
Настройка безопасных cookie для токенов

Для хранения JWT рекомендуется использовать HttpOnly cookies с дополнительными флагами безопасности. HttpOnly предотвращает доступ к токену через JavaScript, снижая риск кражи при XSS. Флаг Secure ограничивает передачу cookie только через HTTPS, исключая утечку данных в нешифрованных сетях.
Флаг SameSite контролирует, в каких сценариях cookie отправляется вместе с запросами. Значения Strict и Lax ограничивают автоматическую отправку токена с кросс-доменных запросов, уменьшая вероятность CSRF.
Рекомендации по настройке безопасных cookie:
- HttpOnly: исключает доступ через JavaScript.
- Secure: обязательная передача по HTTPS.
- SameSite=Strict или Lax: ограничивает отправку cookie при кросс-доменных запросах.
- Ограничение домена и пути: cookie доступна только для определённого поддомена или пути API.
- Короткий срок жизни access-токена: минимизирует ущерб при компрометации.
Дополнительно рекомендуется хранить refresh-токены отдельно и реализовать безопасный механизм их обновления через серверный endpoint, чтобы минимизировать риск злоупотребления украденными токенами.
Когда стоит обновлять токен и где безопаснее хранить обновленный

Access-токены JWT имеют ограниченный срок жизни, обычно 5–15 минут, чтобы уменьшить последствия компрометации. Обновление токена следует проводить перед истечением срока действия или при обнаружении подозрительной активности в сессии.
Рекомендуемая схема обновления:
- Хранить access-токен в HttpOnly cookie с коротким сроком жизни.
- Refresh-токен хранить отдельно, также в HttpOnly cookie, с более длительным сроком действия (обычно 7–30 дней).
- Обновление access-токена происходит через защищённый серверный endpoint, который проверяет валидность refresh-токена.
Преимущества такого подхода:
- Access-токен обновляется автоматически без участия пользователя.
- Снижается риск длительного хранения украденного токена, так как access-токен короткоживущий.
- Refresh-токен защищён HttpOnly и SameSite флагами, что минимизирует риск XSS и CSRF.
Дополнительно следует учитывать логику принудительного аннулирования refresh-токена при подозрительных действиях и реализацию механизма блокировки всех связанных access-токенов при необходимости.
Вопрос-ответ:
Почему не стоит хранить JWT в localStorage?
LocalStorage доступен через JavaScript, что делает токен уязвимым к XSS-атакам. Любой скрипт на странице может получить токен и использовать его для доступа к API. Кроме того, localStorage не удаляет данные автоматически при закрытии вкладки или браузера, что увеличивает риск длительной компрометации. Для защиты рекомендуется использовать HttpOnly cookie с коротким сроком жизни access-токена.
Какая разница между хранением токена в sessionStorage и localStorage?
SessionStorage сохраняет данные только в рамках одной вкладки и автоматически очищается после её закрытия, что снижает риск долгосрочной утечки токена. LocalStorage сохраняет токены до явного удаления, что делает их доступными для других вкладок и сохраняет их после закрытия браузера. SessionStorage подходит для кратковременных токенов, тогда как localStorage требует дополнительных мер защиты.
Как правильно настроить cookie для безопасного хранения JWT?
Cookie для JWT должны быть HttpOnly, чтобы исключить доступ через JavaScript, и Secure, чтобы передаваться только по HTTPS. Флаг SameSite (Strict или Lax) ограничивает автоматическую отправку cookie при кросс-доменных запросах, снижая риск CSRF. Дополнительно рекомендуется ограничить домен и путь cookie, использовать короткий срок жизни access-токена и хранить refresh-токен отдельно с аналогичными флагами безопасности.
Когда стоит обновлять токен и как безопасно хранить обновлённый?
Access-токены с коротким сроком действия нужно обновлять до истечения времени жизни или при подозрительных действиях. Обновление производится через защищённый серверный endpoint с проверкой refresh-токена, который хранится отдельно в HttpOnly cookie с длительным сроком действия. Такой подход позволяет минимизировать риск использования устаревшего или украденного токена и автоматически поддерживать доступ пользователя без вмешательства.
