Эффективный способ подписи полезной нагрузки в HTML5 SPA

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

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

На данный момент мы внедрили подпись RSA, когда наш бэкэнд добавляет подпись полезной нагрузки, используя свой закрытый ключ, а наш клиент HTML5 проверяет ее, используя запеченный открытый ключ. Однако процесс генерации подписи занимает 250 мс (для относительно небольшой полезной нагрузки), и из-за характера подписанного запроса это время неприемлемо.

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

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

Фронтенд — это Javascript, а бэкэнд — Java.


person PentaKon    schedule 01.04.2019    source источник


Ответы (2)


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

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

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

Вы говорите о процессе генерации подписи, но процесс проверки подписи на стороне клиента тоже очень важен в вашем случае, т.к. общее время ожидания пользователем результата складывается из времени на подпись и времени на проверку подпись (более того, подпись часто можно ожидать на сервере, если данные для подписи не генерируются динамически, но никогда нельзя ожидать проверки). Поэтому вам нужен быстрый способ проверки подписи на стороне клиента. Во-первых, подписывайте хэш, а не всю полезную нагрузку. Затем выберите самый быстрый алгоритм асимметричной подписи, доступный в вашей среде разработки, на стороне клиента. Обратите внимание, что проверка подписи RSA выполняется быстрее, чем проверка подписи DSA или ECDSA, для соответствующих длин ключей, соответствующих тому же уровню безопасности. Таким образом, вы должны остаться с RSA.

Все это до этой строки может не так уж вам помочь! Теперь есть способ повысить производительность с помощью RSA для подписи и проверки подписей, и этот способ довольно похож на тот, который реализует SSL/TLS для повышения производительности браузера при загрузке нескольких страниц или других объектов с одного и того же сервера: используйте кеш сеанса. Вы делитесь общим секретом для определенного сеанса с одним конкретным пользователем. Никогда не используйте этот общий секрет для других сессий. Когда пользователь подключается в первый раз, используйте RSA только один раз, чтобы обменять эфемерный общий секрет или обменяться материалом DH для создания этого общего секрета. Затем каждый раз, когда серверу необходимо подписать объект, он создает код аутентификации сообщения с хеш-ключом с этим конкретным секретом. Поэтому, если пользователь находит секрет, например, используя режим отладки своего браузера, это не проблема: этот секрет здесь только для того, чтобы помочь ему узнать, что что-то, поступающее с сервера, не было изменено. Таким образом, пользователь не может использовать этот секрет для изменения обмена данными между сервером и другими пользователями.

person Alexandre Fenyo    schedule 08.04.2019
comment
Ответ не относится к нашему варианту использования. В нашем сценарии атакующим является сам пользователь. Если он откроет сеть и найдет общий секрет, он сможет повторно подписать полезную нагрузку, отправленную из нашего бэкэнда, и вместо {isLicensed: false} заменить ее на {isLicensed: true} и предоставить действительную подпись для этой новой полезной нагрузки, изменив поведение нашего клиента. Я понимаю, что наш вариант использования странный, потому что, по сути, мы пытаемся защитить себя от наших клиентов, а не от стороннего хакера. Единственное, на что мы можем положиться, — это наше шифрование байт-кода Java, все остальное можно проверить. - person PentaKon; 09.04.2019

В итоге мы использовали TweetNaCl как на стороне клиента, так и на стороне сервера. Библиотека предоставляет все простые и быстрые способы обмена общими секретами, подобные DH, без специальной реализации. С эфемерным общим секретом мы можем легко генерировать хэши вместо подписей для наших полезных нагрузок, сократив время обработки с 250 мс до 10 мкс. Также важно, чтобы RSA подписывала первоначальный обмен DH, и это единственное место, где мы используем RSA.

Пожалуйста, прочитайте ответ @AlexandreFenyo, чтобы получить правильную теорию о том, как обычно справляться с такими случаями.

person PentaKon    schedule 09.04.2019