Сторонние атаки через side-channel

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

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

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

Основные каналы утечки:

Временные атаки (timing attacks) Разница во времени выполнения операций может зависеть от секретных данных. Например, ветвление алгоритма RSA в зависимости от значения бита ключа или различная длина обработки больших чисел.

Атаки через кэш и память Хотя в браузере доступ к низкоуровневому кэшу ограничен, косвенные эффекты (например, работа с большими объектами, аллокации BigInt-подобных структур) могут создавать наблюдаемые различия.

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

JIT-оптимизация JavaScript Оптимизирующие компиляторы могут «раскрывать» различия в коде, которые изначально казались нейтральными.


Особенности Jsrsasign и поверхность атаки

Библиотека Jsrsasign реализует криптографические операции (RSA, ECDSA, HMAC, X.509) на JavaScript и используется в средах без нативного WebCrypto или для расширенной функциональности.

Ключевая проблема: JavaScript-реализация не может гарантировать строгую константную временную модель выполнения.

Особенно чувствительные зоны:

  • RSA-операции (возведение в степень с модулем)
  • ECDSA-подпись и проверка
  • обработка BigInteger (внутренне jsbn)
  • сравнение криптографических значений
  • генерация и использование nonce

Timing leakage в RSA-операциях

RSA в Jsrsasign опирается на большие целые числа и модульную экспоненту. В идеальной реализации используется blinding и constant-time exponentiation.

В JavaScript это усложняется:

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

Упрощённая модель RSA-операции:

result = message ^ d mod n

Если реализация экспоненты выполняется через поразрядное возведение в степень, то время работы может зависеть от количества единичных битов в ключе d.

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


Side-channel через ECDSA и проблема nonce

ECDSA чувствителен к утечкам особенно сильно.

Критическая точка — значение k (nonce):

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

Jsrsasign может использовать встроенные генераторы случайных чисел браузера, но проблема возникает при:

  • слабом RNG в окружении
  • повторном использовании seed
  • ошибках интеграции

Детектируемые различия через строки и сравнения

Даже простые операции могут быть источником утечки:

  • сравнение подписи (== вместо constant-time compare)
  • проверка токенов
  • валидация MAC

Обычное сравнение строк:

if (signature === expectedSignature)

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


Jsrsasign и отсутствие строгого constant-time поведения

В отличие от WebCrypto API, Jsrsasign:

  • не гарантирует constant-time операции
  • использует высокоуровневые структуры JS
  • зависит от оптимизаций движка (V8, SpiderMonkey)
  • может менять поведение между версиями браузера

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


Типичные сценарии атак через side-channel

1. Атака по времени проверки подписи

Если сервер использует Jsrsasign для проверки JWT или JWS:

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

2. Атака на сравнение токенов

При проверке API-ключей:

  • различие в 1–2 мкс при совпадении первых символов
  • накопление статистики через тысячи запросов

3. Утечка через ошибки парсинга ASN.1

Jsrsasign активно работает с X.509 и ASN.1 структурами. Разные пути обработки ошибок могут:

  • занимать разное время
  • выбрасывать исключения на разных этапах парсинга
  • раскрывать структуру сертификата

Ограничения JavaScript как среды защиты

JavaScript накладывает фундаментальные ограничения:

  • нет контроля над кэшем CPU
  • нет гарантии тайминга операций
  • garbage collector влияет на временные характеристики
  • JIT может оптимизировать ветвления непредсказуемо

Даже попытки реализовать constant-time в чистом JS остаются статистически уязвимыми.


Практики снижения риска при использовании Jsrsasign

Использование WebCrypto вместо чистого JS

WebCrypto выполняет операции в нативной реализации ОС:

const key = await crypto.subtle.generateKey(
  { name: "RSA-PSS", modulusLength: 2048, hash: "SHA-256" },
  true,
  ["sign", "verify"]
);

Это снижает вероятность side-channel утечек за счёт:

  • аппаратной изоляции
  • constant-time реализаций
  • отсутствия доступа JS к промежуточным состояниям

Минимизация криптографических операций в JS

Jsrsasign допустимо использовать для:

  • парсинга сертификатов
  • тестирования
  • некритичных операций

Недопустимо:

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

Сравнение строк в constant-time стиле

Для предотвращения timing leaks:

function constantTimeEqual(a, b) {
  if (a.length !== b.length) return false;
  let result = 0;
  for (let i = 0; i < a.length; i++) {
    result |= a.charCodeAt(i) ^ b.charCodeAt(i);
  }
  return result === 0;
}

Такой подход убирает ранний выход из цикла.


Контроль источников случайности

Для ECDSA и RSA padding критично:

  • использовать crypto.getRandomValues
  • избегать Math.random
  • не переиспользовать nonce
  • не детерминировать случайность временем или состоянием приложения

Особенности анализа угроз в браузерных приложениях

Side-channel атаки в веб-среде часто имеют форму:

  • cross-origin измерений времени
  • worker-based тайминговых атак
  • event loop наблюдения
  • сетевых задержек как дополнительного канала

Даже если Jsrsasign используется корректно, комбинация с UI-логикой может создавать утечки.


Проблема композиции криптографии и UI-логики

В браузере криптография редко изолирована. Часто она связана с:

  • формами ввода
  • асинхронными запросами
  • рендерингом интерфейса

Любая задержка:

  • валидации формы
  • отображения ошибки
  • ответа API

может стать измеряемым сигналом.


Влияние JavaScript-движков

Разные движки ведут себя по-разному:

  • V8 (Chrome, Node.js) агрессивно оптимизирует циклы
  • SpiderMonkey (Firefox) иначе обрабатывает BigInt-like операции
  • JavaScriptCore (Safari) имеет собственные особенности JIT

Это создаёт дополнительный уровень неопределённости, который затрудняет анализ безопасности Jsrsasign в реальных условиях.


Ограниченность защиты на уровне библиотеки

Даже при идеальной реализации Jsrsasign:

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

Поэтому side-channel безопасность в JavaScript определяется не только кодом библиотеки, но и всей экосистемой исполнения.