Безопасно ли хранить jwt в localStorage с помощью reactjs?

163

В настоящее время я создаю одностраничное приложение с использованием reactjs. Я читал, что многие причины неиспользования localStorage связаны с уязвимостями XSS. Поскольку React экранирует все данные, вводимые пользователем, будет ли теперь безопасно использовать localStorage?

Калоян Косев
источник
4
предпочитаю Session Storage
Пранит Рохида
3
«Не рекомендуется хранить конфиденциальную информацию в локальном хранилище». -OWASP «хранить их в памяти без какого-либо постоянства» -Auth0
benbotto
Я думаю, что Auth0, возможно, изменил свою точку зрения на это - потому что я не могу найти приведенную выше цитату в предоставленной ссылке
DauleDK
Честно говоря, @DauleDK, я думаю, что эта конкретная цитата отсутствует не потому, что Auth0 теперь думает, что это безопасно, а совсем наоборот - если вы читаете эту страницу, теперь кажется, что они советуют, чтобы токен никогда не был сохраняется в решении только на стороне клиента, независимо от используемого метода сохранения: «Если у вас есть SPA без соответствующего внутреннего сервера, ваш SPA должен запрашивать новые токены при входе в систему и сохранять их в памяти без какого-либо постоянства. Для выполнения вызовов API, тогда ваш SPA будет использовать копию токена в памяти ".
NotTheDr01ds,

Ответы:

158

В большинстве современных одностраничных приложений нам действительно нужно хранить токен где-нибудь на стороне клиента (наиболее распространенный вариант использования - чтобы пользователь оставался в системе после обновления страницы).

Всего доступно 2 варианта: веб-хранилище (хранилище сеансов, локальное хранилище) и файл cookie на стороне клиента. Оба варианта широко используются, но это не значит, что они очень безопасны.

Том Эбботт хорошо резюмирует безопасность JWT sessionStorage и localStorage :

Веб-хранилище (localStorage / sessionStorage) доступно через JavaScript в том же домене. Это означает, что любой JavaScript, запущенный на вашем сайте, будет иметь доступ к веб-хранилищу, и из-за этого может быть уязвим для атак межсайтового скриптинга (XSS) . Вкратце, XSS - это тип уязвимости, при которой злоумышленник может внедрить JavaScript, который будет работать на вашей странице. Базовые атаки XSS пытаются внедрить JavaScript через входные данные формы, где злоумышленник помещает <script>alert('You are Hacked');</script>в форму, чтобы увидеть, запущена ли она в браузере и может ли она просматриваться другими пользователями.

Чтобы предотвратить XSS, общий ответ - уйти и закодировать все ненадежные данные. React (в основном) делает это за вас! Вот отличное обсуждение того, за какой уровень защиты от XSS-уязвимостей отвечает React .

Но это не покрывает все возможные уязвимости! Другая потенциальная угроза - использование JavaScript, размещенного в CDN или внешней инфраструктуре .

И снова Том:

Современные веб-приложения включают сторонние библиотеки JavaScript для A / B-тестирования, воронки продаж / анализа рынка и рекламы. Мы используем менеджеры пакетов, такие как Bower, для импорта кода других людей в наши приложения.

Что делать, если скомпрометирован только один из используемых вами скриптов? Вредоносный код JavaScript может быть встроен на страницу, и веб-хранилище будет скомпрометировано. Эти типы XSS-атак могут поразить любое веб-хранилище, которое посещает ваш сайт без их ведома. Вероятно, поэтому группа организаций советует не хранить ничего ценного и не доверять какой-либо информации в веб-хранилище. Сюда входят идентификаторы сеанса и токены.

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

Калоян Косев
источник
11
Итак, если я правильно вас понимаю, вы рекомендуете куки? Просто чтобы убедиться. Благодарность!
SuperLemon
9
Да. Я рекомендую файлы cookie из-за дополнительной безопасности, которую они обеспечивают, и простоты защиты от CSRF с помощью современных веб-фреймворков. Веб-хранилище (localStorage / sessionStorage) уязвимо для XSS, имеет большую площадь поверхности атаки и может повлиять на всех пользователей приложения при успешной атаке.
Калоян Косев
52
Я думаю, вы это перепутали? Современные веб-фреймворки имеют мощную встроенную защиту от XSS. Но не столько для xsrf. Лучшая защита для xsrf - полностью избегать использования файлов cookie. Локальное хранилище привязано к определенному домену, что означает, что домен злоумышленника не может получить к нему доступ. Веб-фреймворки защищаются от xss путем автоматического кодирования и очистки пользовательского ввода. См. Angular.io/guide/security
mikejones1477 07
52
Если «вы рекомендуете файлы cookie [вместо этого]», то могу ли я порекомендовать вам сказать это где-нибудь в ответе? А не просто в комментариях?
Spechter
8
Я здесь немного опоздал, просто читаю эти темы сейчас, и меня смущает одна вещь, многие люди говорят о том, что вы защищены с помощью cookie только http, если вас компрометируют с Xss, но, если у вас есть xss злоумышленнику не нужно ничего вас красть, он может просто сделать сообщение со страницы, чтобы выдать себя за вас, используя этот файл cookie (даже если он не может его украсть). Я что-то упускаю???
Borja Alvarez
39

Я знаю, что это старый вопрос, но, согласно тому, что сказал @ mikejones1477, современные библиотеки и фреймворки переднего плана избегают текста, обеспечивая защиту от XSS. Причина, по которой файлы cookie не являются безопасным методом использования учетных данных, заключается в том, что файлы cookie не предотвращают CSRF, когда это делает localStorage (также помните, что файлы cookie также доступны с помощью javascript, поэтому XSS здесь не является большой проблемой), этот ответ возобновляет почему .

Причина, по которой сохранение токена аутентификации в локальном хранилище и ручное добавление его к каждому запросу защищает от CSRF, заключается в ключевом слове: manual. Поскольку браузер не отправляет этот токен аутентификации автоматически, если я захожу на evil.com и ему удастся отправить POST http://example.com/delete-my-account , он не сможет отправить мой токен аутентификации, поэтому запрос игнорируется.

Конечно, httpOnly - это святой Грааль, но вы не можете получить доступ из reactjs или любой js-фреймворк, кроме того, что у вас все еще есть уязвимость CSRF. Моя рекомендация - localstorage, или если вы хотите использовать файлы cookie, убедитесь, что вы реализуете какое-то решение вашей проблемы CSRF, как это делает django .

Что касается CDN, убедитесь, что вы не используете какие-то странные CDN, например CDN, такие как google или bootstrap, обслуживаются сообществом и не содержат вредоносный код, если вы не уверены, вы можете просмотреть.

Маурисио Кортасар
источник
4
Не уверен, почему вы все еще уязвимы для CSRF при использовании файлов cookie. Использование куки с флагами HttpOnly SameSite=strictи secureсохранит информацию, которую вы установили в куки. Затем против XSS вы просто убедитесь, что ваш JavaScript не знает никаких данных, связанных с аутентификацией, таких как токены и пароли (то есть не храните их в веб-хранилище) - если вы импортируете вредоносный скрипт, этот скрипт не будет иметь доступа к конфиденциальным данным. Да, у вас тоже не будет доступа к токену через JS, но это действительно не должно быть проблемой.
miphe 05
@miphe, вот что я сказал. Но OP запрашивает доступ из javascript. Здесь я просто объясняю, как лучше всего хранить токен, доступный из js.
Маурисио Кортасар
26

В принципе, можно хранить JWT в локальном хранилище.

И я считаю, что это хороший способ. Если мы говорим о XSS, XSS с использованием CDN, это также потенциальный риск получить логин / пропуск вашего клиента. Хранение данных в локальном хранилище, по крайней мере, предотвратит атаки CSRF.

Вам нужно знать и то, и другое и выбирать то, что вы хотите. Обе атаки - это еще не все, о чем вам нужно знать, просто помните: ВСЕ ВАШЕ ПРИЛОЖЕНИЕ ТАКЖЕ БЕЗОПАСНО, КАК НАИМЕНЕЕ БЕЗОПАСНОСТИ ВАШЕГО ПРИЛОЖЕНИЯ.

Еще раз, хранение в порядке, будьте уязвимы для XSS, CSRF, ... не

Алексей Лялька
источник
3
Вот почему безопасно делать следующее: - Хранить JWT в файле cookie, чтобы его нельзя было получить из XSS - Хранить токен CSRF в localStorage, чтобы его нельзя было получить из CSRF
Алехандро Кавасос,
44
Вы поднимаете хороший вопрос: если на вашем сайте запущен вредоносный скрипт, игра все равно окончена. Они могут просто привязать события нажатия клавиш к входам типа пароля и таким образом украсть информацию аутентификации вашего пользователя (что намного, намного хуже, чем кража токена аутентификации JWT). Хранение JWT в localStorage мало что дает для увеличения и без того огромного возможного ущерба от XSS.
Карл Лет
Если метод аутентификации не является одноразовым кодом, без пароля или двухфакторной аутентификацией
Хуан Керри,
8

Это небезопасно, если вы используете CDN:

Вредоносный JavaScript может быть встроен на страницу, и веб-хранилище будет скомпрометировано. Эти типы XSS-атак могут поразить любое веб-хранилище, которое посещает ваш сайт без их ведома. Вероятно, поэтому группа организаций советует не хранить ничего ценного и не доверять какой-либо информации в веб-хранилище. Сюда входят идентификаторы сеанса и токены.

через штормовую тропу

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

Стивен Л
источник
7
Если я не планирую использовать cdns, тогда это будет безопасно?
1
Автор статьи никогда не делал различий между XSS на сайтах, обслуживаемых через CDN или напрямую с центрального сервера. Разве ваше объяснение здесь не применимо в целом, а не только для CDN?
Влад
Любой включенный вами пакет npm - это js, работающий в вашем Интернете.
Хуан Керри,
5

Localstorage разработан для доступа с помощью javascript, поэтому не обеспечивает никакой защиты от XSS. Как упоминалось в других ответах, существует множество возможных способов выполнить XSS-атаку, от которой локальное хранилище по умолчанию не защищено.

Однако файлы cookie имеют флаги безопасности, которые защищают от атак XSS и CSRF. Флаг HttpOnly предотвращает доступ javascript на стороне клиента к cookie, флаг Secure позволяет браузеру передавать cookie только через ssl, а флаг SameSite гарантирует, что cookie отправляется только источнику. Хотя я только что проверил, и SameSite в настоящее время поддерживается только в Opera и Chrome, поэтому для защиты от CSRF лучше использовать другие стратегии. Например, отправка зашифрованного токена в другом файле cookie с некоторыми общедоступными пользовательскими данными.

Таким образом, файлы cookie - более безопасный выбор для хранения данных аутентификации.

Иван
источник
cant get: как HttpOnly может защитить вас от CSRF?
Alex
@AlexLyalka Не имел в виду, что HttpOnly предотвращает CSRF, а не все флаги cookie вместе могут защищать от XSS и CSRF. SameSite обеспечивает некоторую защиту, предотвращая отправку файлов cookie на сайт, отличный от источника. Хотя я только что проверил, поддержка этого флага очень низкая. Также можно избежать CSRF с отдельным зашифрованным токеном с некоторой идентификацией пользователя, которая проверяется на сервере.
Иван
1
Что ж, если кто-то может выполнять код в вашей сети, не может ли он просто сделать сообщение в вашей сети от имени вашего пользователя? Хорошо, он не может получить ваши файлы cookie только для http, но он может совершать звонки, используя эти файлы cookie, так что я все еще не могу понять суть
Борха Альварес
3
@BorjaAlverez Есть большая разница. Да, через XSS кто-то может делать запросы от имени вошедшего в систему пользователя, но компрометация токена еще хуже. Например: токен может предоставлять доступ к API, которые клиентское приложение не использует; токен может содержать другую информацию о пользователе (адрес электронной почты, профиль и гранты); токен может быть использован для атак на ваше приложение; токен может быть передан как id_token_hintсерверу аутентификации OIDC; токен предоставляет злоумышленнику информацию о шифре, который был использован для его подписи; и др.
benbotto 05
5

Чтобы взглянуть на это, нужно принять во внимание уровень риска или вреда.

Вы создаете приложение без пользователей, POC / MVP? Вы стартап, которому нужно быстро выйти на рынок и протестировать свое приложение? Если да, я бы, вероятно, просто реализовал самое простое решение и сосредоточился на поиске продукта, подходящего для рынка. Используйте localStorage, так как его часто проще реализовать.

Вы создаете приложение версии 2 с большим количеством активных пользователей в день или приложение, от которого люди / компании сильно зависят. Будет ли взломать мало места для восстановления или нет? Если это так, я бы внимательно посмотрел на ваши зависимости и подумал о том, чтобы сохранить информацию токена в файле cookie только для http.

Использование как localStorage, так и хранилища файлов cookie / сеансов имеет свои плюсы и минусы.

Как указано в первом ответе: если ваше приложение имеет XSS-уязвимость, ни одна из них не защитит вашего пользователя. Поскольку большинство современных приложений имеют дюжину или более различных зависимостей, становится все труднее гарантировать, что одна из зависимостей вашего приложения не будет уязвима для XSS.

Если в вашем приложении есть XSS-уязвимость и хакер смог ее использовать, хакер сможет выполнять действия от имени вашего пользователя. Хакер может выполнять запросы GET / POST, получая токен из localStorage, или может выполнять запросы POST, если токен хранится в файле cookie только для http.

Единственным недостатком хранения вашего токена в локальном хранилище является то, что хакер сможет прочитать ваш токен.

ХенокГ
источник
1

Разве файлы cookie localStorage или httpOnly неприемлемы? Что касается скомпрометированной сторонней библиотеки, единственное известное мне решение, которое уменьшит / предотвратит кражу конфиденциальной информации, - это принудительная целостность субресурсов .

Целостность субресурсов (SRI) - это функция безопасности, которая позволяет браузерам проверять, что ресурсы, которые они извлекают (например, из CDN), доставляются без неожиданных манипуляций. Он работает, позволяя вам предоставить криптографический хэш, которому должен соответствовать выбранный ресурс.

Пока скомпрометированная сторонняя библиотека активна на вашем веб-сайте, кейлоггер может начать сбор информации, такой как имя пользователя, пароль и все, что вы вводите на сайт.

Файл cookie httpOnly предотвратит доступ с другого компьютера, но ничего не сделает, чтобы помешать хакеру манипулировать компьютером пользователя.

Тихий
источник
0

Большинство ответов на этот вопрос (включая принятый) говорят в пользу традиционных файлов cookie, а localStorage объявляется небезопасным способом хранения ваших конфиденциальных данных. Но это неправда. localStorage так же безопасен, как и традиционные файлы cookie. JavaScript также может получать доступ к файлам cookie, так как можно сказать, что файлы cookie безопасны, а localStorage - нет?

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

Более того, CSRF обсуждался в других ответах, но здесь это совершенно не имеет значения. Защита CSRF служит другой (но бесполезной) цели. Если вы собираетесь создать надежную защиту от XSS в своем коде, вы можете доверять localStorage как безопасное место для ваших учетных данных для аутентификации.

В этом документе больше говорится о возможностях перехвата сеанса, и в основном он фокусируется на файлах cookie.

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

Рехмат
источник
-16

Хранить токен в localStorage безопасно, если вы его зашифруете. Ниже представлен сжатый фрагмент кода, показывающий один из многих способов сделать это.

    import SimpleCrypto from 'simple-crypto-js';

    const saveToken = (token = '') => {
          const encryptInit = new SimpleCrypto('PRIVATE_KEY_STORED_IN_ENV_FILE');
          const encryptedToken = encryptInit.encrypt(token);

          localStorage.setItem('token', encryptedToken);
     }

Затем перед использованием вашего токена расшифруйте его, используя PRIVATE_KEY_STORED_IN_ENV_FILE

Кидали Кевин
источник
@HassanAltha, если вы упускаете суть, никогда не будет 100% безопасного приложения, просто вы уменьшите поверхность атаки, и, по крайней мере, файл env не будет напрямую опубликован на github. Кроме того, связанный код будет обфусцирован и искажен, что затрудняет их поиск злоумышленниками.
Кидали Кевин
1
Закрытый ключ не должен быть раскрыт. Вы поставите под угрозу весь API.
Hassan Althaf
По моему опыту, если вы все сделали разумно и правильно, ваш закрытый ключ не будет отображаться в вашей производственной сборке, если так, снимок экрана для поддержки этого или даже URL-адреса.
Кидали Кевин
1
@ Lo-Tan, когда код внешнего интерфейса будет скомпилирован, переменная process.env будет разрешена и помещена в код. Если он не будет разрешен, браузер не узнает о своей переменной env. Таким образом открывается его закрытый ключ.
Фабиан,
1
@Fabian Думаю, я бы никогда не подумал отправить закрытый ключ клиенту и почему-то не заметил, что localStorage упоминается несколько раз (код и комментарий). Ой! Да, не делайте этого, ребята.
Ло-Тан