В SJCL параметр итераций напрямую связан с функциями получения ключа
из пароля, прежде всего с PBKDF2 (sjcl.misc.pbkdf2). Его
роль — искусственно увеличить вычислительную стоимость подбора пароля,
делая каждую попытку атакующего дороже по времени и ресурсам.
Итерация в этом контексте — это повторное применение криптографической хэш-функции. Если одна операция хэширования занимает условно 1 единицу времени, то 100 000 итераций превращают её в 100 000 единиц. При этом линейное увеличение параметра почти линейно увеличивает время легитимного вычисления и атаки перебором.
Функция PBKDF2 в SJCL выглядит так:
sjcl.misc.pbkdf2(password, salt, iterations, keyLength)
Параметр iterations задаёт число циклов HMAC-SHA256 (или
другой выбранной хэш-функции).
Ключевая особенность: каждое увеличение iterations одинаково влияет и на пользователя, и на атакующего. Поэтому выбор значения — это компромисс между безопасностью и удобством.
Выбор числа итераций определяется не абстрактной “рекомендованной цифрой”, а моделью атаки:
Итерации критически важны именно во втором случае.
Оценка защиты может быть выражена через простую модель:
Стоимость атаки ∝ iterations × стоимость одного PBKDF2
Если атакующий имеет GPU/ASIC-ускорение, выигрыш пользователя от увеличения iterations сохраняется, но не линейно — разрыв уменьшается.
Исторически PBKDF2 использовался с очень низкими значениями (1000–10000), что сегодня считается недостаточным.
Современные ориентиры зависят от среды:
Основное ограничение — блокировка UI потока JavaScript.
JavaScript выполняется в основном потоке (если не использовать Web Workers). Это означает:
Практический критерий:
время вычисления PBKDF2 не должно превышать 100–500 мс в клиентском режиме без worker’ов
Поэтому iterations подбирается не только по безопасности, но и по измеренному времени выполнения.
В SJCL нет автоматического выбора оптимального iterations, поэтому применяется ручная калибровка:
Пример логики:
function calibrate(password, salt) {
let t0 = performance.now();
sjcl.misc.pbkdf2(password, salt, 1000);
let t1 = performance.now();
let timePerIteration = (t1 - t0) / 1000;
let targetTime = 200; // ms
return Math.floor(1000 * (targetTime / timePerIteration));
}
Это упрощённая модель, но она отражает ключевую идею: итерации — это производная от времени, а не фиксированная константа.
Важно учитывать, что стоимость одной итерации не одинакова:
PBKDF2 относительно плохо защищён от GPU, так как не содержит memory-hard компонентов. Поэтому увеличение iterations — это лишь частичная защита.
SJCL также поддерживает scrypt, где параметры заменяют iterations более сложной моделью:
N — CPU/memory costr — block sizep — parallelization factorВ отличие от PBKDF2:
Это делает scrypt более устойчивым к GPU-атакам при сопоставимых задержках.
На практике вводится два порога:
Если превышен интерактивный порог:
Фиксированное маленькое значение (например, 1000) → устаревшая безопасность
Слишком большое значение без теста → зависание браузера
Игнорирование различий устройств → на слабых устройствах деградация UX
Отсутствие обновления параметров со временем → со временем GPU делает атаки дешевле
Выбор iterations в SJCL обычно сводится к следующей логике:
Со временем вычислительные мощности растут, и фиксированное значение iterations теряет силу. Это приводит к эффекту:
реальная стойкость ∝ iterations / вычислительная мощность атакующего
Поэтому системы, использующие SJCL, должны учитывать необходимость миграции параметров при обновлении данных или смене пароля.
Итерации — это линейный регулятор стоимости. Он удобен, но ограничен:
В системах с высокими требованиями к защите обычно комбинируют:
Так формируется многоуровневая модель, где iterations остаются только одной из составляющих стоимости атаки.