Хранение и передача ключей

В симметричных алгоритмах, которые активно используются через CryptoJS (AES, DES, TripleDES), один и тот же ключ применяется как для шифрования, так и для расшифрования данных. Это делает вопрос хранения и передачи ключей критически важным: компрометация ключа автоматически означает компрометацию всех зашифрованных данных.

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

Формирование ключей в CryptoJS

CryptoJS предоставляет несколько способов получения ключевого материала. Наиболее прямой — генерация случайных значений:

const key = CryptoJS.lib.WordArray.random(32);

Такой подход используется, когда ключ генерируется на стороне сервера или в защищённой среде и далее безопасно передаётся или хранится.

Однако в реальных приложениях чаще применяется вывод ключа из пароля пользователя.

Производные ключи и PBKDF2

Одним из наиболее правильных способов формирования ключей является использование PBKDF2 (Password-Based Key Derivation Function 2). Этот механизм позволяет преобразовать слабый пароль в криптографически стойкий ключ.

const key = CryptoJS.PBKDF2(password, salt, {
    keySize: 256 / 32,
    iterations: 10000
});

Ключевые элементы процесса:

  • salt — случайная добавка, предотвращающая использование радужных таблиц
  • iterations — число итераций, увеличивающее стоимость перебора
  • keySize — размер ключа в словах (WordArray)

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

Использование passphrase в CryptoJS

CryptoJS позволяет упростить работу с ключами через параметр passphrase:

const encrypted = CryptoJS.AES.encrypt("data", "secret passphrase");

В этом случае библиотека автоматически:

  • генерирует salt
  • выводит ключ через OpenSSL-совместимый алгоритм
  • формирует IV

Расшифрование выполняется аналогично:

const decrypted = CryptoJS.AES.decrypt(encrypted, "secret passphrase");

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

Хранение ключей на клиентской стороне

Одной из наиболее распространённых ошибок является сохранение ключей в браузере. Основные варианты:

localStorage

Хранение ключа в localStorage является небезопасным по следующим причинам:

  • доступен любому JavaScript-коду на странице
  • уязвим к XSS-атакам
  • не шифруется браузером

sessionStorage

Имеет те же недостатки, но ограничен жизненным циклом вкладки.

IndexedDB

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

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

Передача ключей по сети

Передача ключей через сеть является одной из самых критичных уязвимостей в системе.

Основное правило: ключ не должен передаваться по сети в открытом виде или даже в зашифрованном виде, если есть возможность избежать этого.

Правильные практики:

  • использование HTTPS (TLS обязателен)
  • передача только зашифрованных данных, но не ключей
  • использование протоколов обмена ключами (например, ECDH на серверной стороне)
  • генерация ключей на стороне сервера

Типичная архитектура исключает сам факт передачи симметрического ключа клиенту.

IV и его роль в безопасности передачи

Initialization Vector (IV) не является секретом, но критически важен для безопасности шифрования.

const iv = CryptoJS.lib.WordArray.random(16);

IV должен:

  • быть уникальным для каждой операции
  • храниться вместе с ciphertext
  • не повторяться при использовании одного ключа

Передача IV допустима, но его повторное использование недопустимо.

Серверная модель хранения ключей

В серверных приложениях ключи должны храниться исключительно вне кода:

  • переменные окружения (ENV)
  • секрет-хранилища (Vault, AWS Secrets Manager)
  • аппаратные модули безопасности (HSM)

Прямое включение ключей в исходный код создаёт постоянный риск утечки через репозитории, логи и сборки.

Ротация ключей

Даже при корректной защите ключи должны регулярно обновляться.

Причины:

  • снижение риска длительной компрометации
  • ограничение времени действия украденного ключа
  • соответствие требованиям безопасности

Ротация предполагает:

  • генерацию нового ключа
  • повторное шифрование данных (re-encryption)
  • отключение старого ключа

Типичные ошибки при работе с ключами

На практике встречаются повторяющиеся архитектурные ошибки:

  • использование одного ключа для всех пользователей
  • хранение ключей в клиентском коде
  • отсутствие salt при PBKDF2
  • повторное использование IV
  • передача ключей через API без необходимости
  • использование слабых паролей без KDF

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

Безопасная модель работы с CryptoJS

Корректная схема обычно выглядит следующим образом:

  • ключ генерируется на сервере или выводится из пароля через PBKDF2
  • клиент получает только зашифрованные данные
  • IV и salt передаются вместе с ciphertext
  • ключ не покидает доверенную среду
  • используется HTTPS для всей коммуникации
  • реализована ротация ключей при длительном хранении данных