Очень важным аспектом в мире разработки программного обеспечения является безопасность данных, которые проходят через открытые каналы связи. В наших веб-приложениях происходит интенсивный обмен данными по различным протоколам, таким как http, между клиентскими приложениями, которые представлены в виде браузеров, мобильных и настольных приложений и приложений на стороне сервера. Важность и конфиденциальность данных могут быть разными в зависимости от специфики веб-приложения, а вероятность перехвата третьей стороной возрастает по мере совершенствования методов взлома в мире ИТ. Что можно сделать, чтобы предотвратить доступ к данным вашему слушателю трафика? Если мы обмениваемся данными между клиентскими приложениями и сервером, мы не хотим, чтобы информация хранилась на сервере в виде открытого текста, который будет доступен в случае взлома сервера, социальной инженерии или атаки человека посередине. ». Как этого избежать?

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

В этой статье мы рассмотрим пример реализации обмена зашифрованными сообщениями между серверным приложением и браузером. На этот раз используются алгоритмы AES и RSA. В качестве протокола обмена сообщениями был выбран WebSocket (честно говоря, вначале я просто хотел написать зашифрованный чат в качестве примера, но решил сделать приложение проще и лучше объяснить). В то же время это самая быстрая версия обмена сообщениями между серверной частью и клиентской частью, она помогает писать меньше кода обслуживания и сосредоточиться на процессе шифрования. Клиентская сторона будет представлена ​​веб-браузером, а реализация шифрования будет написана с использованием JavaScript браузера. Серверная часть написана на Nodejs.

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

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

Что касается browser-javascript и Nodejs, то здесь довольно большой выбор библиотек шифрования. Следующие библиотеки рассмотрены в примере ниже:

javascript - WebCryptoAPI

Https://www.w3.org/TR/WebCryptoAPI/

Https://github.com/diafygi/webcrypto-examples

Nodejs - Крипто, и node-rsa

Https://nodejs.org/api/crypto.html

Https://www.npmjs.com/package/node-rsa

В статье возникают следующие вопросы:

1) Основная информация об алгоритмах AES и RSA.

2) Подготовка среды.

3) Генерация публичных и приватных ключей RSA для клиента и сервера с помощью Nodejs.

4) Обмен зашифрованными сообщениями RSA между клиентом и сервером.

5) Генерация ключа AES на стороне сервера и передача в браузер в зашифрованном виде с использованием RSA.

6) Обмен сообщениями AES между клиентом и сервером.

Образец кода доступен по следующему адресу:

Https://github.com/weblab-technology/rsa-aes-client-server-encryption-nodejs-example

1. Основы алгоритмов AES и RSA

AES - это симметричный алгоритм шифрования. Он использует один и тот же ключ для шифрования и дешифрования. Большие объемы данных можно зашифровать с помощью симметричного алгоритма шифрования.

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

Https://en.wikipedia.org/wiki/Initialization_vector

Важным параметром для AES является режим шифрования. Он определяет, как последовательность блоков открытых данных конвертируется в зашифрованные.
Для AES существуют такие режимы: ECB, CBC, РСВС, CFB, OFB, CTR. Подробности:

Https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation

Длина ключа AES составляет 128, 192, 256 бит.

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

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

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

ЮАР-ОАЭП

RSA-PKCS1-v1_5
Более подробную информацию можно найти здесь:

RSA-PKCS1-v1_5

Https://en.wikipedia.org/wiki/Padding_(cryptography)

Https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Padding

Следует отметить, что схема RSA-PKCS1-v1_5 считается недостаточно надежной, лучше использовать RSA-OAEP.

2. Подготовка окружающей среды

Пример обмена зашифрованными сообщениями будет производиться в следующей последовательности:

  1. Клиент расшифровывает сообщение и выводит его на экран. Затем зашифрованное сообщение RSA отправляется на бэкэнд.
  2. Бэкэнд расшифровывает сообщение RSA от клиента и регистрирует его в консоли. Сервер генерирует ключ AES и отправляет его клиенту.
  3. Клиент расшифровывает зашифрованный RSA ключ AES и выводит его на экран. Клиент отправляет на сервер зашифрованное сообщение AES.
  4. Сервер расшифровывает сообщение AES от клиента и регистрирует его на консоли. Сервер отправляет клиенту зашифрованное сообщение AES.
  5. Клиент расшифровывает сообщение AES и выводит его на экран.

Прежде всего, давайте создадим базовую структуру приложения, которая позволит предоставлять html-страницу и обрабатывать веб-узлы. Мы используем расширения для Nodejs: express и socket.io.

Код для этой статьи представлен в этом репозитории: https://github.com/weblab-technology/rsa-aes-client-server-encryption-nodejs-example

Версия Nodejs в этом примере - 6.9.4. Для тех, кто использует docker, используйте файл docker-compose.yml, который можно найти в репозитории примеров (см. Docker-compose).

Обозначим каталог с проектом как APP_ROOT и выполняем следующие шаги:

Сначала создайте APP_ROOT / package.json:

2. Добавьте уверенности:

npm install — save express
npm install — save socket.io

3. Создайте каталог для статического APP_ROOT / static и файл в нем - APP_ROOT / static / index.html, где будет выполняться расчет браузера. Содержимое APP_ROOT / static / index.html:

4. Давайте создадим файл APP_ROOT / index.js, чтобы поместить туда запуск веб-сервера и обработчик подключения к веб-сокетам:

5. Запустите команду node index.js и убедитесь, что все работает, затем откройте браузер и введите localhost: 3000. Теперь пример фона готов, перейдем к вопросам шифрования.

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

3. Генерация публичных и приватных ключей RSA для клиента и сервера с помощью Nodejs.

На этом этапе мы сгенерируем открытый и закрытый ключи для клиента и сервера в формате PEM. Для этого выполните следующие действия:

  1. Создайте следующие папки и файлы:
  • папка APP_ROOT / components /;
  • папка APP_ROOT / keys /;
  • файл APP_ROOT / init.js;
  • файл APP_ROOT / components / rsa-wrapper.js;

2. Для генерации ключей используем библиотеку node-rsa. Установите его:

npm install — save node-rsa

3. Чтобы сгенерировать ключи, вам нужно выбрать большое значение открытой экспоненты. Обычно выбираются простые числа Ферма: 17, 257, 65537. Это значение действует как аргумент функции генерации ключа. Число 65537 - приемлемый компромисс между скоростью и надежностью.

Откройте APP_ROOT / components / rsa-wrapper.js и добавьте следующий код:

Https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation

4. Создайте и откройте файл APP_ROOT / components / init.js:

5. Запустите узел init.js.

Появилось сообщение «Ключи сгенерированы…»

Перейдите в папку APP_ROOT / keys /. Должны быть сгенерированы ключи для клиента и сервера:

  • APP_ROOT / ключи / client.private.pem
  • APP_ROOT / ключи / client.public.pem
  • APP_ROOT / ключи / server.private.pem
  • APP_ROOT / ключи / server.public.pem

6. Скопируйте ключи клиента и открытый ключ сервера в файл APP_ROOT / static / index.html. Перейдите в файл APP_ROOT / static / index.html под тегом body и вставьте разметку:

В текстовое поле вставляем содержимое файлов из APP_ROOT / keys /:

  • textarea id = ”server_public” - APP_ROOT / keys / server.public.pem
  • textarea id = ”client_public” - APP_ROOT / keys / client.public.pem
  • textarea id = ”client_private” - APP_ROOT / keys / client.private.pem

4. Обмен зашифрованными сообщениями RSA между клиентом и сервером.

В этом разделе клиент получит зашифрованное сообщение от сервера, которое расшифровывается и отображается, а затем отправляется обратно (сообщение RSA) на сервер, который сервер расшифровывает. Это так просто :)

  1. Добавить функции в оболочку RSA.

APP_ROOT / components / rsa-wrapper.js:

2. Перейдите в файл APP_ROOT / index.js и добавьте константу:

Перед запуском http-сервера загрузите ключи:

3. Запустите сервер, узел index.js, проверьте, все ли ключи загружаются, и теперь строка будет зашифрована и расшифрована тестовым образцом.

Server public encrypting
Encrypted RSA string
… encrypted format …
Decrypted RSA string …
Server init hello

Отлично, скрипт тестирования шифрования RSA работает на стороне сервера.

4. Теперь перейдите в файл APP_ROOT / index.js, найдите обработчик событий для подключения к веб-сокетам:

Добавьте следующий код на стороне сервера в обработчик событий подключения. Добавляем код для шифрования сообщения с помощью RSA и отправляем клиенту:

5. Теперь посмотрим на код в браузере. Для работы с сообщениями RSA нам понадобится библиотека для кодировок, для этого мы используем внешнюю библиотеку:

Https://github.com/inexorabletash/text-encoding

Это необходимо для работы с преобразованием кодировок текста при работе с зашифрованными сообщениями. Добавьте файлы этой библиотеки:

APP_ROOT / static / js / encoding.js

APP_ROOT / static / js / encoding-indexes.js

APP_ROOT / static / js / converter-wrapper.js - набор методов для преобразования строк base64 в ArrayBuffer и наоборот.

Набор оболочек был создан внутри примера, его нужно просто скопировать в ваш проект из готового примера в репозитории. Использование этих функций связано с тем, что библиотека Web CryptoAPI в браузере имеет такие параметры, как ArrayBuffer, плюс этот тип значений отправляется обратно, и чрезвычайно важно правильно преобразовать эти параметры для работы с их на сервере.

6. Также добавьте оболочку для библиотеки браузера Crypto RSA.

7. Перейдем к APP_ROOT / static / index.html. Добавьте в этот файл необходимые скрипты после подключения socket.io.js

Также добавьте код обработки шифрования:

8. Теперь запустите узел index.js и введите localhost: 3000 в браузере.

Мы увидим сообщение в кодировке base64 в браузере и расшифрованное сообщение с сервера. Все обошлось, браузер понимает RSA-сообщение с сервера. Если мы войдем в консоль выполнения Nodejs, мы увидим сообщение RSA от клиента в зашифрованном виде в формате base64 и в расшифрованном виде. Теперь сервер реализует сообщения RSA от клиента.

5. Генерация ключа AES на стороне сервера и его передача в браузер в зашифрованном виде с помощью RSA.

  1. Создайте оболочку AES для работы с крипто-библиотекой на node.js

2. Затем перейдите в APP_ROOT / index.js и добавьте модуль aesWrapper:

В конец обработчика событий подключения мы добавляем код для генерации ключа AES и его отправку на клиентскую сторону в зашифрованном виде с помощью RSA:

3. На стороне клиента добавьте файл, который будет работать с функциями AES в Web CryptoAPI APP_ROOT / static / js / aes-wrapper.js:

4. Вставьте aes-wrapper.js в APP_ROOT / static / index.html.

Добавить обработчик для приема и расшифровки ключей с сервера

5. Перезагрузите сервер и посмотрите журнал. Вы увидите сообщение с зашифрованным и расшифрованным ключом в формате base64 в base64 (от сервера к клиенту). Миссия выполнена :)

6. Обмен сообщениями AES между клиентом и сервером.

  1. Перейдите в APP_ROOT / index.js. Найдите обработчик подключения к веб-сокету и добавьте обработчик обмена сообщениями AES.

2. Переходим в APP_ROOT / static / index.html и в код получения ключа AES добавляем:

А также:

3. Перезагрузите сервер и посмотрите журнал браузера.

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

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

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

Репозиторий с кодом:

Https://github.com/weblab-technology/rsa-aes-client-server-encryption-nodejs-example

Полезные ссылки:

Https://coolaj86.com/articles/asymmetric-public--private-key-encryption-in-node-js/

Https://coolaj86.com/articles/symmetric-cryptography-aes-with-webcrypto-and-node-js/

Андрей Гус, Backend Developer

Дима Дмитриенко, редактор-маркетолог

с помощью программиста Александра Кныга