Изоляция контекста и защита от XSS

Web Crypto API изначально проектировался с учётом строгой модели безопасности браузера. Все криптографические операции выполняются в пределах изолированного контекста, который ограничен политиками происхождения (Same-Origin Policy) и механизмами контроля доступа к данным.

Ключевая особенность — невозможность прямого доступа к приватным ключам и чувствительным материалам через обычные JavaScript-объекты. Вместо этого используются объекты типа CryptoKey, которые инкапсулируют внутреннее состояние и управляются самим браузером.

const key = await crypto.subtle.generateKey(
  {
    name: "AES-GCM",
    length: 256
  },
  true,
  ["encrypt", "decrypt"]
);

console.log(key); // CryptoKey, а не сырой ключ

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


Флаг extractable и контроль экспорта

Каждый ключ создаётся с параметром extractable, который определяет возможность извлечения его содержимого.

const key = await crypto.subtle.generateKey(
  { name: "AES-GCM", length: 256 },
  false, // ключ нельзя экспортировать
  ["encrypt", "decrypt"]
);

Если extractable: false, попытка экспорта завершится ошибкой:

await crypto.subtle.exportKey("raw", key); // выбросит исключение

Это критический механизм защиты от XSS-атак: даже если вредоносный скрипт получит доступ к объекту CryptoKey, он не сможет извлечь его содержимое.


Работа только в безопасных контекстах

Web Crypto API доступен исключительно в безопасных контекстах (secure contexts), то есть:

  • HTTPS
  • localhost
  • некоторые доверенные среды

Попытка использовать API в небезопасной среде приведёт к отсутствию доступа:

if (!window.crypto || !window.crypto.subtle) {
  throw new Error("Web Crypto API недоступен");
}

Это предотвращает атаки типа man-in-the-middle, при которых трафик может быть перехвачен и модифицирован.


Изоляция через Origin

Все криптографические операции жёстко привязаны к origin (домен + протокол + порт). Ключи, созданные на одном origin, не могут быть использованы на другом.

Пример:

  • https://example.com не может получить доступ к ключам https://api.example.com
  • даже разные порты считаются разными origin

Это защищает от утечек между различными частями приложения или сторонними встроенными ресурсами (iframe).


Использование SubtleCrypto как ограниченного интерфейса

Интерфейс crypto.subtle намеренно минималистичен. Он не предоставляет:

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

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

const encrypted = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv },
  key,
  data
);

Угроза XSS и её влияние на криптографию

XSS (Cross-Site Scripting) остаётся одной из главных угроз для клиентской криптографии. Если злоумышленник внедряет скрипт в страницу, он получает доступ к:

  • DOM
  • JavaScript-контексту
  • объектам CryptoKey

Даже несмотря на защиту от экспорта ключей, XSS может:

  • использовать ключи для шифрования/дешифрования
  • подменять данные перед шифрованием
  • перехватывать открытые данные до их обработки

Пример уязвимого сценария:

const encrypted = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv },
  key,
  sensitiveData
);

При XSS злоумышленник может заменить sensitiveData или перехватить его до вызова.


Защита от XSS при использовании Web Crypto

1. Content Security Policy (CSP)

Один из самых эффективных способов защиты — строгая CSP:

Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  object-src 'none';

Запрещает:

  • inline-скрипты
  • загрузку скриптов с внешних источников

2. Отказ от inline-скриптов

Inline JavaScript — частая причина XSS. Использование только внешних файлов снижает риск:

<script src="app.js"></script>

Вместо:

<script>
  // небезопасно
</script>

3. Использование HttpOnly cookies

Секреты (например, токены) не должны быть доступны через Jav * aScript:

Set-Cookie: session=abc123; HttpOnly; Secure;

Это предотвращает их кражу даже при XSS.


4. Разделение ключей и данных

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

  • localStorage
  • sessionStorage
  • IndexedDB (без необходимости)

Если хранение необходимо, предпочтительно использовать CryptoKey с extractable: false.


5. Минимизация области действия ключей

Каждый ключ должен иметь строго ограниченные права:

["encrypt"] // вместо ["encrypt", "decrypt"]

Это снижает ущерб при компрометации.


6. Использование iframe с sandbox

Критические операции можно изолировать:

<iframe sandbox="allow-scripts"></iframe>

Это создаёт дополнительный уровень изоляции выполнения.


7. Trusted Types

Механизм защиты от XSS, предотвращающий небезопасную работу с DOM:

window.trustedTypes.createPolicy("default", {
  createHTML: (input) => input
});

Позволяет контролировать точки вставки HTML.


Поток данных и защита на уровне архитектуры

Важно учитывать, что Web Crypto API защищает только криптографические операции, но не весь поток данных.

Уязвимости возникают до и после шифрования:

  1. До:

    • ввод пользователя
    • манипуляции DOM
  2. После:

    • вывод расшифрованных данных
    • передача по сети

Рекомендуется:

  • валидировать входные данные
  • использовать строгую типизацию
  • избегать небезопасных API (innerHTML, eval)

Атаки через подмену окружения

При XSS возможно переопределение глобальных функций:

crypto.subtle.encrypt = function() {
  // перехват
};

Защита:

const subtle = crypto.subtle;
Object.freeze(subtle);

Или:

const { encrypt } = crypto.subtle;

Фиксация ссылок снижает риск подмены.


Использование Web Workers для изоляции

Web Workers позволяют выполнять криптографию в отдельном потоке:

const worker = new Worker("crypto-worker.js");

Преимущества:

  • изоляция контекста
  • отсутствие доступа к DOM
  • снижение риска XSS

Передача ключей:

worker.postMessage({ key });

CryptoKey может передаваться, но остаётся защищённым объектом.


Ограничения безопасности Web Crypto API

Несмотря на встроенные механизмы защиты:

  • API не защищает от XSS полностью
  • не предотвращает логические ошибки разработчика
  • не контролирует поток данных вне криптографии

Основная модель безопасности предполагает:

  • доверенный код
  • отсутствие внедрённого скрипта

Практическая модель угроз

При проектировании необходимо учитывать:

Что защищается:

  • приватные ключи
  • зашифрованные данные

От чего защищается:

  • утечка ключей
  • перехват данных

От чего не защищает:

  • выполнение вредоносного JS
  • компрометация страницы

Рекомендованная стратегия

  • Генерация ключей с extractable: false
  • Строгая CSP
  • Изоляция через Workers
  • Минимизация прав ключей
  • Отказ от хранения секретов в открытом виде
  • Контроль точек ввода/вывода данных

Такая комбинация позволяет использовать Web Crypto API максимально безопасно даже в условиях потенциальных XSS-угроз.