Хватит использовать локальное хранилище!

Я серьезно. Перестань.

Я не знаю, что побуждает разработчиков сохранять информацию о сеансах в локальном хранилище (local storage). Но какова бы не была причина, это нужно прекращать.

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

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

Что такое Local Storage?

Local Storage — это такая фича HTML5, которая позволяет разработчику хранить информацию в браузере пользователя с помощью JavaSript.

На практике же, локальное хранилище — это объект JavaScript, который позволяет добавлять и удалять некоторые элементы в него/из него.

Вот пример кода JavaScript, который хранит часть моей личной информации в локальном хранилище, передает ее мне, а затем (необязательно) удаляет:

// You can store data in local storage using either syntax
localStorage.userName = "rdegges";
localStorage.setItem("favoriteColor", "black");

// Once data is in localStorage, it'll stay there forever until it is
// explicitly removed
alert(localStorage.userName + " really likes the color " + localStorage.favoriteColor + ".");

// Removing data from local storage is also pretty easy. Uncomment the lines
// below to destroy the entries
//localStorage.removeItem("userName");
//localStorage.removeItem("favoriteColor");

Если ты запустишь приведенный выше код JavaScript в своем браузере на тестовой HTML-странице, то увидишь фразу “rdegges really likes the color black.” в предупреждающем сообщении. Если ты затем откроешь инструменты разработчика, то сможешь увидеть, что переменные userName и favoriteColor хранятся в локальном хранилище твоего браузера:

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

HTML5 и тут прикроет твою спину, в нем есть штука, которая называется sessionStorage. Вот это сессионное хранилище работает точно так же, как и локальное хранилище, за исключением того, что все данные, которые оно хранит, автоматически удаляются, когда пользователь закрывает вкладку браузера.

Что хорошего в локальном хранилище?

Теперь, когда ты в курсе, что такое локальное хранилище, давай поговорим о том, что делает его крутым! Несмотря на то, что вся цель этой статьи состоит в том, чтобы отговорить тебя от его использования для хранения данных сеанса, локальное хранилище все же имеет некоторые интересные свойства.

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

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

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

Еще одна приятная вещь в локальном хранилище — это то, что у него не такое сильное ограничение по размеру, как у файлов cookie. Локальное хранилище обеспечивает по крайней мере 5 Мб хранения данных во всех основных веб-браузерах, что чертовски намного больше, чем 4 КБ (максимальный размер), которые ты можешь хранить в файле cookie.

Это делает локальное хранилище особенно полезным, если ты хочешь кэшировать некоторые данные приложения в браузере для последующего использования. Поскольку 4 КБ (у cookie) — это не так уж много, локальное хранилище — один из твоих реальных альтернативных вариантов.

Что плохого в Local Storage?

ОК. Мы говорили о хорошем, теперь давайте поговорим минуту (или две!) о плохом.

Локальное хранилище — это оооочень просто. ВОТ ТАК. Локальное хранилище — это невероятно простой API.

Мне кажется, что большинство разработчиков не понимают, насколько на самом деле просты локальные хранилища:

  • Оно может хранить только строковые данные. Это делает его довольно бесполезным для хранения данных, которые даже немного сложнее, чем простая строка. И конечно, ты можешь сериализовать все, включая типы данных, в локальное хранилище.
  • Оно синхронно. Это означает, что каждая локальная операция хранения будет выполняться по одному за раз. Для сложных приложений это лучше не использовать, так как это замедлит время выполнения приложения.
  • Оно не может использоваться веб-воркерами. Это означает, что если ты хочешь создать приложение, которое использует преимущества фоновой обработки для повышения производительности, расширения chrome и тому подобные вещи: ты вообще не можешь использовать локальное хранилище, так как оно недоступно для веб-воркеров.
  • Он по-прежнему ограничивает размер данных, которые ты можешь хранить (~5 Мб во всех основных браузерах). Это довольно низкий предел для людей, создающих приложения, которые требуют больших объемов данных или которые должны функционировать в автономном режиме.
  • Любой код JavaScript на Вашей странице может получить доступ к локальному хранилищу: локальное хранилище не имеет никакой защиты данных вообще. Это большой вопрос по соображениям безопасности.

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

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

Почему небезопасно хранить конфиденциальные данные в Local Storage

Вот в чем дело: большинство плохих вещей о локальном хранилище не так уж и важны. Ты все еще можешь выйти сухим из воды, используя его, но у тебя будет только немного более медленное приложение и незначительное раздражение. Но безопасность — это другое. Модель безопасности локального хранилища действительно важно знать и понимать, так как она значительно повлияет на твой сайт способами, которые ты можешь и не осознавать.

И все дело в том, что локальное хранилище не является безопасным! Вовсе нет! Все, кто использует локальное хранилище для хранения конфиденциальной информации, такой как данные сеанса, данные пользователя, данные кредитной карты (даже временно!) и все остальное (что ты не хотел бы выкладывать в соцсети) делает это неправильно.

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

Что самое опасное во всем мире? Вот именно! JavaScript (:)).

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

На самом деле проблема сводится к межсайтовым скриптовым атакам (XSS). Я не буду утомлять тебя полным объяснением XSS, но вот поверхностно:

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

Теперь ты можешь подумать «Ну и что? Мой сайт защищен. Ни один злоумышленник не может запустить JavaScript на моем сайте.»

И это разумный довод. Если твой сайт действительно безопасен и никакой злоумышленник не может запустить код JavaScript на нем, то ты технически в безопасности, но на самом деле это невероятно трудно достичь. Позволь мне объяснить.

Если твой сайт содержит какой-либо сторонний код JavaScript, включенный из источника за пределами вашего домена:

  • Ссылки bootstrap
  • Ссылки jQuery
  • Ссылки Vue, React, Angular и т. д.
  • Ссылки на любой код рекламной сети
  • Ссылки на Google Analytics
  • Ссылки на любой код отслеживания

Тогда ты в настоящее время подвергаешься риску того, что злоумышленник запустит JavaScript на твоем веб-сайте. Допустим, ваш сайт имеет следующий тег сценария:

<script src="https://awesomejslibrary.com/minified.js"></script>

В этом случае, если awesomejslibrary.com компрометируется и их minified.js скрипт будет изменен на код, который собирает твои данные и отправляет на свой сайт, то тогда ты полностью облажался. В этой ситуации злоумышленник легко компрометирует все, что ты хранил в локальном хранилище, и ты никогда этого не заметишь.

Как инженеры, я думаю, мы часто склонны думать, что мы никогда не будем внедрять сторонний JavaScript в наши веб-сайты. Но в реальном мире этот сценарий редко реализуется.

В большинстве компаний маркетинговая команда непосредственно управляет публичным сайтом, используя различные редакторы WYSIWYG и инструменты. Можешь ли ты действительно быть уверенным, что нигде на вашем сайте не используешь сторонний JavaScript? Я бы сказал «Нет».

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

PSA: Не храни JSON Web Tokens в Local Storage

Хотя я чувствую, что ясно дал понять, что ты никогда не должен хранить конфиденциальную информацию в локальном хранилище в предыдущем разделе, я чувствую необходимость специально поговорить про веб-токены JSON (JWTs).

Самые большие нарушители безопасности, которых я вижу сегодня, — это те из нас, кто хранит JWTs (данные сеанса) в локальном хранилище. Многие люди не понимают, что JWTs-это, по сути, то же самое, что имя пользователя/пароль.

Если злоумышленник может получить копию твоего JWT, он может сделать запрос на веб-сайт от твоего имени, и ты никогда не узнаешь об этом. Относись к своим JWTs, как к номеру кредитной карты или паролю: никогда не храни их в локальном хранилище.

Существуют тысячи учебных пособий, видеороликов YouTube и даже классы программирования в университетах и буткемпах кодирования, которые неправильно учат новых разработчиков хранить JWTs в локальном хранилище в качестве механизма аутентификации. ЭТА ИНФОРМАЦИЯ НЕВЕРНА. Если ты видишь, что кто-то говорит тебе сделать это, БЕГИ!

Что использовать вместо локального хранилища?

Итак, со всеми недостатками локального хранилища, что же использовать вместо этого? Давай рассмотрим альтернативы!

Sensitive Data

Если нужно хранить конфиденциальные данные, ты всегда должен использовать сеанс (cookie) на стороне сервера. Конфиденциальные данные включают в себя:

  • User IDs
  • Session IDs
  • JWTs
  • Personal information
  • Credit card information
  • API keys
  • Любую другую информацию, которую ты бы не хотел запостить в соц сетях

Если нужно хранить конфиденциальные данные, вот как это сделать:

  • Когда пользователь входит на сайт, создай для него идентификатор сеанса и сохрани его в криптографически подписанном файле cookie. Если ты используешь веб-фреймворк, посмотри раздел “Как создать сеанс пользователя с помощью файлов cookie » и следуйте этому руководству.
  • Убедись, что любая библиотека файлов cookie, используемая твоим веб-фреймворком, устанавливает флаг файлов cookie httpOnly. Этот флаг делает невозможным для браузера чтение любых файлов cookie, что необходимо для безопасного использования сеансов на стороне сервера с файлами cookie. Прочтите статью Джеффа Этвуда для получения дополнительной информации
  • Убедись, что твоя библиотека cookie также устанавливает флаг SameSite=strict cookie (для предотвращения CSRF-атак), а также флаг secure=true (для обеспечения того, чтобы файлы cookie можно было устанавливать только по зашифрованному соединению).
  • Каждый раз, когда пользователь делает запрос на твой сайт, используй его идентификатор сеанса (извлеченный из файла cookie, который он отправляет), чтобы получить данные учетной записи либо из базы данных, либо из кэша (в зависимости от размера сайта)

Как только ты получишь информацию об учетной записи пользователя и проверишь ее, не стесняйся извлекать любые связанные с ней конфиденциальные данные.

Нестроковые Данные

Если нужно хранить в браузере данные, которые не являются конфиденциальными и не являются чисто строковыми данными, лучшим вариантом для является IndexedDB. Это API, который позволяет работать с хранилищем объектов типа базы данных в браузере.

Что замечательно в IndexedDB, так это то, что ты можешь использовать его для хранения типизированной информации: целых чисел, плавающих и т. д. Ты также можешь определить первичные ключи, обрабатывать индексацию и создавать транзакции, чтобы предотвратить проблемы целостности данных.

Отличный учебник для изучения (и использования) IndexedDB — это учебник Google.

Автономные данные

Если нужно, чтобы приложение работало в автономном режиме, лучше всего использовать комбинацию IndexedDB (выше) вместе с API кэша (который является частью Service Workers).

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

Отличный учебник для изучения (и использования) API кэша — это учебник Google.

Please Stop Using Local Storage

Теперь, когда у нас появилось понимание локального хранилища, я надеюсь, ты осознаешь, почему (вероятно) не следует его использовать.

Если только не нужно хранить общедоступную информацию, которая:

  • Совсем не чувствительна
  • Не нужно использовать в сверхвысоком производительном приложении
  • Не больше 5 Мбайт
  • Состоит из чисто строковых данных

… не используй локальное хранилище! Используй правильный инструмент для работы.

И пожалуйста, пожалуйста, что бы ты ни делал, не храни информацию о сеансе (например, веб-токены JSON) в локальном хранилище. Это очень плохая идея и откроет чрезвычайно широкий спектр атак, которые могут искалечить твоих пользователей.

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

И да, я не единственный, кто считает, что вы никогда не должны хранить что-либо чувствительное в локальном хранилище. Подробнее тут.

Перевод статьи

Наш Телеграмм канал

Возможно, Вам понравится:

guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x
()
x