Одной из ключевых проблем при использовании симметричного шифрования в браузере и Node.js становится преобразование пароля пользователя в криптографический ключ. В библиотеке Crypto-js эта задача не решена на уровне архитектурного принуждения: разработчик получает инструменты, но вся ответственность за корректное применение KDF ложится на него.
Пароль пользователя почти никогда не является криптографически стойким материалом. Даже если он кажется сложным, его энтропия существенно ниже требуемой для AES-ключей (128/192/256 бит).
Типичная ошибка выглядит так:
const key = CryptoJS.enc.Utf8.parse(password);
const encrypted = CryptoJS.AES.encrypt("secret data", key);
В этом случае:
Любой перебор словаря выполняется мгновенно на GPU, поскольку криптографическая стойкость фактически заменяется стойкостью пароля.
KDF (Key Derivation Function) предназначена для преобразования слабого входного значения (пароля) в криптографически стойкий ключ.
Её задачи:
В идеале используются современные KDF:
Crypto-js предоставляет базовую реализацию PBKDF2:
const salt = CryptoJS.lib.WordArray.random(128/8);
const key = CryptoJS.PBKDF2(password, salt, {
keySize: 256/32,
iterations: 10000
});
Однако важно понимать ограничения:
Одна из наиболее критичных проблем — повторное использование пароля без соли:
const key = CryptoJS.PBKDF2(password, "static_salt", {
iterations: 1000
});
Последствия:
Соль должна быть:
PBKDF2 увеличивает стойкость за счёт вычислительной нагрузки. Часто встречается опасная практика:
iterations: 1000
Это значение давно считается недостаточным.
Проблема:
Реалистичный диапазон:
Crypto-js не навязывает безопасный путь использования. Это означает:
В результате безопасность становится не свойством библиотеки, а дисциплиной разработчика.
| Подход | Стойкость | Проблема |
|---|---|---|
| AES(password) | низкая | нет KDF |
| PBKDF2(10k) | средняя | устаревшие параметры |
| PBKDF2(300k + salt) | приемлемая | нет memory-hard защиты |
| Argon2 | высокая | не поддерживается Crypto-js |
Минимально корректная реализация с Crypto-js:
const salt = CryptoJS.lib.WordArray.random(16);
const key = CryptoJS.PBKDF2(password, salt, {
keySize: 256 / 32,
iterations: 300000,
hasher: CryptoJS.algo.SHA256
});
const encrypted = CryptoJS.AES.encrypt(data, key.toString());
Дополнительно необходимо:
Даже при использовании PBKDF2 атаки становятся эффективными из-за:
Если пароль слабый (например, словарный), KDF лишь немного замедляет атаку, но не предотвращает её.
Ключевая слабость Crypto-js в современном контексте — отсутствие алгоритмов, требующих большого объёма памяти.
Argon2 и scrypt делают атаку дорогой не только по CPU, но и по памяти. PBKDF2:
Использование Crypto-js с паролями в браузере приводит к системным рискам:
Особенно критично это для:
Если Crypto-js используется в системе, где есть пароли пользователей, необходимо:
Слабые пароли и отсутствие устойчивого KDF-подхода превращают криптографическую защиту в иллюзию безопасности, где основным фактором становится не алгоритм, а человеческий выбор пароля.