Токены JWT - это круто, но как их безопасно хранить в вашем интерфейсе? Мы рассмотрим плюсы и минусы localStorage и файлов cookie.

В моем последнем посте мы рассмотрели, как работает OAuth 2.0, и изучили, как генерировать токены доступа и обновлять токены. Теперь мы рассмотрим, как хранить токены в вашем интерфейсе.

Токены доступа обычно представляют собой недолговечные токены JWT, которые подписываются вашим сервером и включаются в каждый HTTP-запрос к вашему серверу для его авторизации. Токены обновления обычно представляют собой долговечные непрозрачные строки, которые хранятся в вашей базе данных и используются для получения нового токена доступа по истечении срока его действия.

Где мне хранить свои токены во внешнем интерфейсе?

Есть два распространенных способа хранения ваших токенов. Первый находится в localStorage, а второй - в файлах cookie. Существует много споров о том, какой из них лучше, и большинство людей склоняются к файлам cookie, поскольку они более безопасны.

Давайте рассмотрим сравнение localStorage и файлов cookie. Эта статья в основном основана на этой статье и комментариях к этому посту.

Локальное хранилище

Плюсы: удобно.

  • Это чистый JavaScript, и это удобно. Если у вас нет серверной части и вы полагаетесь на сторонний API, вы не всегда можете попросить сторонний API установить определенный файл cookie для вашего сайта.
  • Работает с API, которые требуют, чтобы вы поместили свой токен доступа в заголовок, например: Authorization Bearer ${access_token}.

Минусы: уязвим для XSS-атак.

Атака XSS происходит, когда злоумышленник может запустить JavaScript на вашем веб-сайте. Это означает, что злоумышленник может забрать токен доступа, который вы сохранили в своем localStorage. XSS-атака может произойти из-за стороннего кода JavaScript, включенного в ваш сайт, такого как React, Vue, jQuery, Google Analytics и т. Д. Практически невозможно не включить на свой сайт какие-либо сторонние библиотеки.

Печенье

Плюсы: файл cookie недоступен через JavaScript; следовательно, он не так уязвим для XSS-атак, как localStorage.

  • Если вы используете httpOnly и secure файлы cookie, это означает, что к вашим файлам cookie нельзя получить доступ с помощью JavaScript, поэтому, даже если злоумышленник может запустить JS на вашем сайте, он не сможет прочитать ваш токен доступа из файла cookie.
  • Он автоматически отправляется в каждом HTTP-запросе на ваш сервер.

Минусы: в зависимости от варианта использования вы не сможете хранить свои токены в файлах cookie.

  • Максимальный размер файлов cookie составляет 4 КБ. Поэтому, если вы используете большой токен JWT, сохранение в файле cookie не вариант.
  • Существуют сценарии, когда вы не можете поделиться файлами cookie со своим сервером API или API требует, чтобы вы поместили токен доступа в заголовок авторизации. В этом случае вы не сможете использовать файлы cookie для хранения своих токенов.

О XSS-атаке

Локальное хранилище уязвимо, потому что оно легко доступно с помощью JavaScript, и злоумышленник может получить ваш токен доступа и использовать его позже. Однако, хотя httpOnly файлы cookie недоступны с помощью JavaScript, это не означает, что с помощью файлов cookie вы защищены от XSS-атак с использованием вашего токена доступа.

Если злоумышленник может запустить JavaScript в вашем приложении, он может просто отправить HTTP-запрос на ваш сервер, который автоматически включит ваши файлы cookie; Это просто менее удобно для злоумышленников, потому что они не могут прочитать содержимое токена, хотя им редко приходится. Для злоумышленника также может быть более выгодно атаковать с помощью браузера жертвы (просто отправив этот HTTP-запрос), а не с помощью машины злоумышленника.

Файлы cookie и CSRF-атака

Атака 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

тогда злоумышленник может легко создать form на вредоносном веб-сайте, который отправляет запрос POST на https://site.com/email/change со скрытым полем электронной почты, и автоматически включается session cookie. Однако это можно легко уменьшить, используя флаг sameSite в вашем файле cookie и добавив токен анти-CSRF.

Итак, как мне использовать файлы cookie для сохранения моих токенов OAuth 2.0?

Подведем итоги: вот различные способы хранения токенов:

  • Вариант 1. Храните токен доступа в localStorage: подвержен XSS-атакам.
  • Вариант 2. Сохраните свой токен доступа в httpOnly cookie: подвержен CSRF, но может быть смягчен, немного лучше с точки зрения воздействия XSS.
  • Вариант 3. Сохраните токен обновления в httpOnly cookie: в безопасности от CSRF, немного лучше с точки зрения воздействия XSS.

Мы рассмотрим, как работает вариант 3, поскольку он лучший из трех.

Вариант 3. Сохраните токен доступа в памяти и сохраните токен обновления в файле cookie.

Почему это безопасно от CSRF? Хотя форма, отправленная на /refresh_token, будет работать и будет возвращен новый токен доступа, злоумышленник не сможет прочитать ответ, если он использует форму HTML. Чтобы злоумышленник не смог успешно выполнить fetch или AJAX запрос и прочитать ответ, необходимо правильно настроить политику CORS сервера авторизации для предотвращения запросов с неавторизованных веб-сайтов.

Итак, как это работает?

Шаг 1. Верните токен доступа и обновите токен, когда пользователь аутентифицирован.

После аутентификации пользователя сервер авторизации вернет access_token и refresh_token. access_token будет включен в тело ответа, а refresh_token будет включен в файл cookie.

Обновить настройки cookie токена:

  • Используйте флаг httpOnly, чтобы JavaScript не читал его.
  • Используйте флаг secure=true, чтобы его можно было отправлять только по HTTPS.
  • По возможности используйте флаг SameSite=strict, чтобы предотвратить CSRF. Это можно использовать только в том случае, если сервер авторизации имеет тот же сайт, что и ваш интерфейс. Если это не так, то ваш сервер авторизации должен установить заголовки CORS в серверной части или использовать другие методы, чтобы гарантировать, что запрос токена обновления может выполняться только авторизованными веб-сайтами.

Шаг 2. Сохраните токен доступа в памяти

Хранение токена в памяти означает, что вы помещаете этот токен доступа в переменную на своем интерфейсном сайте. Да, это означает, что токен доступа исчезнет, ​​если пользователь переключится на другую вкладку или обновит сайт. Вот почему у нас есть токен обновления.

Шаг 3. Продлите токен доступа с помощью токена обновления

Когда токен доступа исчез или истек, нажмите конечную точку /refresh_token, и токен обновления, который был сохранен в файле cookie на шаге 1, будет включен в запрос. Затем вы получите новый токен доступа, который сможете использовать для своих запросов API. Это означает, что ваш токен JWT может быть больше 4 КБ, и вы также можете поместить его в заголовок авторизации.

Заключение

Хотя файлы cookie все еще имеют некоторые уязвимости, этот метод предпочтительнее, чем localStorage, когда это возможно. Это связано с тем, что и localStorage, и файлы cookie уязвимы для XSS-атак, но злоумышленнику труднее атаковать, когда вы используете httpOnly файлы cookie. Кроме того, файлы cookie уязвимы для атак CSRF, но эту угрозу можно уменьшить с помощью флага sameSite и токенов анти-CSRF. Наконец, вы все равно можете заставить его работать, даже если вам нужно использовать заголовок Authorization: Bearer или если ваш JWT больше 4 КБ.

Это также соответствует рекомендации сообщества OWASP:

Не храните идентификаторы сеансов в локальном хранилище, поскольку данные всегда доступны для JavaScript. Файлы cookie могут снизить этот риск с помощью флага httpOnly.

- OWASP: шпаргалка по безопасности HTML5

Это оно!

Это должно охватывать основы и помочь вам защитить свой сайт.

Ресурсы

При написании этого блога мы ссылались на несколько статей, особенно из этих статей:

Вопросы и отзывы

Если вам нужна помощь или у вас есть отзывы, пожалуйста, оставьте комментарий здесь!

Этот пост написан командой Cotter - беспарольный вход на ваш сайт или в приложение.