Вопрос или проблема
Здравствуйте, сообщество InformationSecurity!
У меня следующая ситуация, и я ищу советы по нашей архитектуре безопасности.
Я работаю с клиентом, который создает приложение для составления резюме, где пользователи могут вводить свои данные (например, электронную почту, номера телефонов, имя и фамилию, опыт работы и другую информацию, связанную с резюме) на сайте, нажимать кнопку загрузки и получать резюме в виде файла.
В настоящее время мы сохраняем данные пользователя в localStorage и indexedDb, а не на наших серверах. Наша текущая реализация шифрует все данные на клиенте с помощью ключа шифрования, сгенерированного сервером, который не хранится на клиенте. Однако у меня есть сомнения, так как я знаю, что localStorage (и в принципе все другие типы хранения на клиенте) уязвимы для атак XSS. Таким образом, возникает вопрос 🙂
Процесс сохранения данных в настоящее время работает следующим образом:
Предполагая, что пользователь авторизован в нашем приложении. Под шифрованием/дешифрованием я имею в виду: AES-GCM
- Клиент отправляет запрос на наш сервер для получения секрета шифрования/дешифрования. Запрос включает токен аутентификации
- Наш сервер проверяет подпись токена аутентификации. Если подпись токена действительна, сервер извлекает userId из токена
- Наш сервер генерирует randomKey длиной 32 байта
- Этот случайный ключ + userId в комбинации с секретом на стороне сервера используются для получения ключа шифрования. encryptionKey=PBKDF2(PBKDF2(serverSideSecret, userId), randomKey)
- Этот ключ шифрования и случайный ключ возвращаются в браузер
- Случайный ключ сохраняется в localStorage, ключ шифрования остается в закрытой переменной модуля ES6, который не экспортируется. Сам ключ шифрования не сохраняется в любом клиентском хранилище
- Данные шифруются с использованием ключа, зашифрованный текст сохраняется в localStorage браузера.
Получение из хранилища:
- Случайный ключ считывается из localStorage
- Клиент отправляет запрос на получение ключа дешифрования для данных. Запрос содержит токен аутентификации, а также случайный ключ из шага 1
- Сервер проверяет токен, если он действителен, генерирует секрет для дешифрования из userId: decryptionSecret= PBKDF2(PBKDF2(serverSideSecret, userId), randomKey)
- Ключ дешифрования возвращается клиенту, который может дешифровать данные
- DOM заполняется зашифрованными данными. Пользователь может продолжить редактировать их
Главная идея в том, что мой клиент не хочет сохранять никаких данных, связанных с клиентом, на стороне сервера. Используя процесс выше, фактически каждый раз, когда данные сохраняются в localStorage, они будут зашифрованы новым ключом шифрования (поскольку каждый раз будет сгенерирован новый случайный ключ), который можно получить только с сервера с действительным токеном аутентификации.
Но у меня есть ощущение, что существуют некоторые уязвимости в безопасности. Я прав?
Ответ или решение
Эффективность шифрования localStorage/indexedDB с использованием серверного секрета, производимого через PBKDF2
Введение
Вопрос безопасности данных в веб-приложениях стал более актуальным, чем когда-либо. По мере увеличения объема личной информации, которую пользователи хранят и обрабатывают в онлайн-среде, разработчики приложений должны быть особенно внимательными к архитектуре безопасности. Данный ответ предназначен для обсуждения, насколько безопасно используемое вами шифрование данных в localStorage и indexedDB, а также выявления возможных уязвимостей в вашем текущем подходе.
Текущая Архитектура Шифрования
Система, предложенная вами, включает в себя несколько ключевых этапов:
- Клиент запрашивает шифровальный секрет у сервера, предоставляя токен аутентификации.
- Сервер проверяет токен и генерирует новый
randomKey
, который используется вместе сuserId
и серверным секретом для созданияencryptionKey
с использованием PBKDF2. randomKey
сохраняется в localStorage, в то время какencryptionKey
хранится только в памяти клиента.- Данные шифруются с использованием
encryptionKey
и сохраняются в localStorage.
Оценка Уязвимостей
Несмотря на то, что ваша система шифрования имеет свои достоинства, существуют некоторые уязвимости, которые могут быть рассмотрены:
-
Уязвимость к XSS-атакам: Хранение любых ключей шифрования на стороне клиента (даже временных) делает приложение уязвимым для XSS-атак. Если злоумышленник сможет внедрить скрипт, он сможет получить доступ к
randomKey
в localStorage, а значит, и к данным, которые можно расшифровать. -
Сетевая передача данных: Каждый раз, когда вы передаете
randomKey
, есть риск его перехвата. Это особенно актуально, если не используются защищенные протоколы (например, HTTPS). -
Ошибка аутентификации: Без надлежащего контроля над токенами аутентификации, даже мимолетная утечка токена может предоставить доступ к процессу шифрования/дешифрования.
-
Сложность управления ключами: Каждый раз, когда создаётся новый
randomKey
, возникает необходимость управления множеством ключей. Это увеличивает шансы на ошибки и неправильно использованные ключи.
Рекомендации по Усилению Безопасности
Для повышения уровня безопасности вашего приложения, вот несколько рекомендаций, которые можно рассмотреть:
-
Предотвращение XSS:
- Используйте Content Security Policy (CSP) для ограничения источников исполняемого кода.
- Проводите регулярные аудиты на предмет уязвимостей, чтобы выявлять и устранять потенциальные XSS-угрозы.
-
Шифрование данных перед отправкой:
- Рассмотрите возможность начального шифрования данных перед их отправкой на сервер или перед сохранением в localStorage. Это может уменьшить количество данных, доступных в открытом виде.
-
Кэширование токенов:
- Реализуйте механизм, который будет ограничивать валидность токенов аутентификации и их использование, что помогает минимизировать риск перехвата.
-
Использование защищенных соединений:
- Всегда используйте HTTPS для передачи данных между клиентом и сервером, чтобы предотвратить несанкционированный доступ к данным.
-
Регулярное обновление ключей шифрования:
- Рассмотрите внедрение механизма периодической ротации ключей шифрования, чтобы снизить последствия их компрометации.
Заключение
Ваша текущая система шифрования данных с использованием PBKDF2 и AES-GCM содержит важные элементы безопасности. Тем не менее, наличие уязвимостей, связанных с хранением randomKey
в localStorage и потенциальными рисками XSS, делает необходимым пересмотр подхода к безопасности данных. Важно внедрять дополнительные меры защиты и регулярно проверять архитектуру безопасности в соответствии с современными стандартами. Заключительной рекомендацией будет непрерывное внимание к ресурсам, которые могут помочь выявить и исправить уязвимости, и к образованию команды в вопросах безопасной разработки.