Ответ
Выбор между хранением JWT в cookie и передачей через заголовок Authorization — это компромисс между удобством и безопасностью, в частности, защитой от XSS и CSRF атак.
Хранение в cookie
Токен автоматически отправляется браузером с каждым запросом на тот же домен.
-
Плюсы:
- Защита от XSS: Если установить флаг
HttpOnly, токен становится недоступным для JavaScript на клиенте, что является основной защитой от кражи токена через XSS-уязвимости. - Простота: Не требует дополнительного кода на клиенте для прикрепления токена к запросам.
- Защита от XSS: Если установить флаг
-
Минусы:
- Уязвимость к CSRF (Cross-Site Request Forgery): Поскольку браузер отправляет cookie автоматически, злоумышленник может заставить пользователя выполнить нежелательное действие на вашем сайте со стороннего ресурса. Для защиты необходимо использовать
SameSiteатрибут (StrictилиLax) и/или CSRF-токены.
- Уязвимость к CSRF (Cross-Site Request Forgery): Поскольку браузер отправляет cookie автоматически, злоумышленник может заставить пользователя выполнить нежелательное действие на вашем сайте со стороннего ресурса. Для защиты необходимо использовать
# Пример установки защищенного cookie в Flask
response.set_cookie(
'access_token',
value=jwt_token,
httponly=True, # Защита от XSS
secure=True, # Отправка только по HTTPS
samesite='Lax' # Защита от CSRF
)
Хранение в localStorage / sessionStorage и передача в Authorization header
Токен хранится в веб-хранилище браузера и вручную прикрепляется к каждому API-запросу.
-
Плюсы:
- Защита от CSRF: Токен не отправляется автоматически, поэтому CSRF-атаки невозможны.
- Гибкость: Легко работает с разными доменами и поддоменами. Является стандартом для API, используемых мобильными и нативными приложениями.
-
Минусы:
- Уязвимость к XSS: Если на сайте есть XSS-уязвимость, злоумышленник может выполнить JS-код, который украдет токен из
localStorageи отправит на свой сервер. - Требует реализации: Необходимо писать код на клиенте (например, interceptor в Axios) для добавления заголовка
Authorization: Bearer <token>ко всем защищенным запросам.
- Уязвимость к XSS: Если на сайте есть XSS-уязвимость, злоумышленник может выполнить JS-код, который украдет токен из
// Пример отправки запроса с токеном из localStorage
const token = localStorage.getItem('jwt_token');
fetch('/api/data', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
Рекомендация:
- Для традиционных веб-приложений (server-side rendering) предпочтительнее использовать
cookieс флагамиHttpOnly,SecureиSameSite=Strict. - Для Single Page Applications (SPA) и мобильных клиентов чаще используется
Authorizationheader. Для повышения безопасности в SPA рекомендуется хранить токен в памяти приложения, а не вlocalStorage, чтобы минимизировать окно для XSS-атак.
Ответ 18+ 🔞
А, ну это же классический спор, блядь, про куки и заголовки! Вечная тема, как "Муму" у Тургенева, только про токены, ёпта. Слушай, сейчас разложу по полочкам, чтобы ты не был, как Герасим, немой и в замешательстве.
Вариант первый: Сунуть токен в куки.
Это как если бы ты, блядь, прибил табличку "Муму" к собаке на ошейник, и она сама везде с ней ходит. Браузер её автоматом таскает в каждый запрос на твой домен.
-
Что хорошего, ёбушки-воробушки?
- От XSS защищает, как танк. Ставишь флажок
HttpOnly— и всё, пиши пропало! Никакой твой кривой JavaScript до этого токена не доберётся, хоть ты тресни. Кража через XSS — в пизду. - Проще некуда. На клиенте нихуя не надо париться, не надо писать код, который этот токен цепляет. Всё само летит.
- От XSS защищает, как танк. Ставишь флажок
-
А где подвох, хитрая жопа?
- CSRF, блядь, вылезает. Раз куки сами летят, значит, злоумышленник может с левого сайта заставить браузер юзера наделать делов на твоём. Как защищаться? Ну,
SameSiteатрибут в помощь (StrictилиLax), или ещё CSRF-токены городить.
- CSRF, блядь, вылезает. Раз куки сами летят, значит, злоумышленник может с левого сайта заставить браузер юзера наделать делов на твоём. Как защищаться? Ну,
# Вот так, например, во Flask эту защищённую печеньку запихивают
response.set_cookie(
'access_token',
value=jwt_token,
httponly=True, # Руки прочь, JavaScript! Защита от XSS.
secure=True, # Только по HTTPS, ёпта, не по этому вашему HTTP.
samesite='Lax' # Чтоб от CSRF хоть как-то
)
Вариант второй: Запихнуть в localStorage и таскать в заголовке Authorization.
Это уже как если бы Герасим носил Муму в мешке за пазухой и только по надобности доставал, показывал и говорил "Му!". Хранишь сам, отправляешь сам.
-
Чем это, блядь, круто?
- CSRF похуй. Токен сам по себе не летит, значит, заставить его улететь со стороннего сайта — нихуя не выйдет. Защита от этой хуйни — наше всё.
- Гибкость — овердохуища. Легко работает с кучей доменов, поддоменов. Это ж стандарт де-факто для API, которые ещё и в мобилках крутятся.
-
А чем тогда, сука, плохо?
- XSS тут как тут, пиздец. Нашёл злодей дыру, выполнил свой скрипт — и всё, токен из
localStorageвытащил и себе на сервак отправил. И прощай, безопасность. - Надо городить. На клиенте теперь обязан писать код, который к каждому запросу этот заголовок прилепляет. Interceptor в Axios или свою обёртку над
fetch.
- XSS тут как тут, пиздец. Нашёл злодей дыру, выполнил свой скрипт — и всё, токен из
// Смотри, как это обычно выглядит. Достал и прицепил.
const token = localStorage.getItem('jwt_token'); // Достаём из того самого уязвимого места
fetch('/api/secret-data', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`, // Вручную прилепил
'Content-Type': 'application/json'
}
});
Так что в итоге, ёпта? Рекомендация, блядь:
- Если у тебя обычное веб-приложение, где страницы на сервере рендерятся — бери куки (
HttpOnly,Secure,SameSite=Strict). Безопасно и просто, как топор Герасима. - Если пишешь SPA (одностраничное приложение) или делаешь API для мобилок — тут чаще заголовок
Authorization. А чтобы XSS не съел, в SPA можно токен вообще в памяти приложения держать, а не вlocalStorageвалять. Сложнее, но безопаснее. Волнение, блядь, чувствую, ты уже понял.