- PVSM.RU - https://www.pvsm.ru -
JWT (JSON Web Token) — это замечательный стандарт, основанный на формате JSON, позволяющий создавать токены доступа, обычно используемые для аутентификации в клиент-серверных приложениях. При использовании этих токенов возникает вопрос о том, как безопасно хранить их во фронтенд-части приложения. Этот вопрос нужно решить сразу же после того, как токен сгенерирован на сервере и передан клиентской части приложения.
Материал, перевод которого мы сегодня публикуем, посвящён разбору плюсов и минусов использования локального хранилища браузера (localStorage
) и куки-файлов для хранения JWT.
Существует 2 распространённых способа хранения токенов на клиенте: локальное хранилище браузера и куки-файлы. О том, какой способ лучше, много спорят. Большинство людей склоняется в сторону куки-файлов из-за их лучшей защищённости.
Давайте сравним локальное хранилище и куки-файлы. Наше сравнение основано, преимущественно, на этом [2] материале и на комментариях к нему.
Основное преимущество локального хранилища заключается в том, что им удобно пользоваться.
Authorization Bearer ${access_token}
.Главный недостаток локального хранилища — это его уязвимость к XSS-атакам.
localStorage
.Главное преимущество куки-файлов заключается в том, что они недоступны из JavaScript. В результате они не так уязвимы к XSS-атакам, как локальное хранилище.
HttpOnly
и защищённые куки-файлы, это означает, что из JavaScript нельзя получить доступ к этим файлам. То есть, если даже атакующий сможет запустить свой код на вашей странице, ему не удастся прочитать токен доступа из куки-файла.В зависимости от конкретных обстоятельств может случиться так, что токены в куки-файлах сохранить не удастся.
Authorization
. В таком случае вы не сможете хранить токены в куки-файлах.Локальное хранилище уязвимо к XSS-атакам из-за того, что с ним очень легко работать, используя JavaScript. Поэтому злоумышленник может получить доступ к токену и воспользоваться им в своих интересах. Однако, хотя HttpOnly-куки и недостижимы из JavaScript, это не означает, что вы, используя куки, защищены от XSS-атак, направленных на кражу токена доступа.
Если атакующий может запускать свой JS-код в вашем приложении, это значит, что он может просто отправить вашему серверу запрос, а токен будет включён в этот запрос автоматически. Такая схема работы просто не так удобна для атакующего, так как он не может прочитать содержимое токена. Но подобное нужно атакующим нечасто. Кроме того, при такой схеме работы злоумышленнику может быть выгоднее атаковать сервер, пользуясь компьютером жертвы, а не собственным.
CSRF-атаки — это атаки, в ходе которых пользователя каким-то образом принуждают к выполнению особого запроса. Например, сайт принимает запросы на изменение адреса электронной почты:
POST /email/change HTTP/1.1
Host: site.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
Cookie: session=abcdefghijklmnopqrstu
email=myemail.example.com
В такой ситуации атакующий может создать форму со скрытым полем для ввода адреса электронной почты, которая отправляет POST-запрос на https://site.com/email/change
. При этом сессионные куки автоматически будут включены в такой запрос.
Правда, от этой угрозы можно легко защититься, использовав атрибут SameSite
в заголовке ответа и анти-CSRF [3] токены.
Хотя и куки-файлы не отличаются полной неуязвимостью к атакам, для хранения токенов лучше всего, всегда, когда это возможно, выбирать именно их, а не localStorage
. Почему?
SameSite
и анти-CSRF [3] токены.
Куки-файлами можно пользоваться даже в тех случаях, когда надо применять заголовок Authorization: Bearer
, или когда JWT больше 4 Кб. Это, кроме того, согласуется с рекомендациями [4] OWASP: «Не храните идентификаторы сессий в локальном хранилище, так как соответствующие данные всегда доступны из JavaScript. Куки-файлы могут помочь снизить риск благодаря HttpOnly
».
Давайте кратко перечислим способы хранения токенов:
Ниже мы подробнее рассмотрим третий способ хранения токенов, так как он, из трёх перечисленных, выглядит самым интересным.
Злоумышленник может создать форму, которая обращается к /refresh_token
. В ответ на этот запрос возвращается новый токен доступа. Но атакующий не может прочитать ответ в том случае, если он использует HTML-форму. Для того чтобы не дать атакующему успешно выполнять fetch- или AJAX-запросы и читать ответы, нужно, чтобы CORS-политика сервера авторизации была бы настроена правильно, а именно — так, чтобы сервер не реагировал бы на запросы от неавторизованных веб-сайтов.
Как всё это настроить?
После того, как пользователь аутентифицируется, сервер аутентификации возвращает access_token
(токен доступа) и refresh_token
(токен обновления). Токен доступа будет включён в тело ответа, а токен обновления — в куки.
Вот что нужно использовать для настройки куки-файлов, предназначенных для хранения токенов обновления:
HttpOnly
— чтобы не дать прочесть токен из JavaScript.secure=true
, что приведёт к тому, что данные будут передаваться только по HTTPS.SameSite=strict
нужно использовать всегда, когда это возможно, что позволит защититься от CSRF-атак. Этот подход может использоваться только в том случае, если сервер авторизации относится к тому же сайту, что и фронтенд системы. Если это не так, тогда сервер авторизации должен устанавливать CORS-заголовки на бэкенде, или использовать другие методы для того чтобы убедиться в том, что запрос с токеном обновления может быть выполнен только авторизованным веб-сайтом.Хранение токена доступа в памяти означает, что токен, в коде фронтенда, записывают в переменную. Это, конечно, означает, что токен будет утерян в том случае, если пользователь закроет вкладку, на которой открыт сайт, или обновит страницу. Именно поэтому у нас имеется токен обновления.
Если токен доступа оказывается утраченным или недействительным, нужно обратиться к конечной точке /refresh_token
. При этом токен обновления, который, на шаге 1, был сохранён в куки-файле, будет включён в запрос. После этого вы получите новый токен доступа, который сможете использовать для выполнения запросов к API.
Всё это значит, что JWT могут быть больше 4 Кб, и то, что их можно помещать в заголовок Authorization
.
То, о чём мы тут рассказали, должно дать вам базовую информацию о хранении JWT на клиенте, и о том, как сделать ваш проект безопаснее.
Как вы храните JWT на клиенте?
Автор: ru_vds
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka/355565
Ссылки в тексте:
[1] Image: https://habr.com/ru/company/ruvds/blog/512866/
[2] этом: https://dev.to/rdegges/please-stop-using-local-storage-1i04
[3] анти-CSRF: https://owasp.org/www-community/Anti_CRSF_Tokens_ASP-NET
[4] рекомендациями: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html
[5] Источник: https://habr.com/ru/post/512866/?utm_source=habrahabr&utm_medium=rss&utm_campaign=512866
Нажмите здесь для печати.