Technical Технические документы

Подробная техническая документация по криптографическим

Опубликовано: 16 апреля 2025 г. Последнее обновление: 16 апреля 2026 г. Версия: 2.0

Технические документы Index

  1. Сквозное шифрование при передаче файлов
  2. Privacy-First Cryptographic Document подписание

Сквозное шифрование при передаче файлов

PDF Pro Whitepaper WP-001 — Архитектура and Безопасность

1.1 Аннотация

В этом техническом документе описана архитектура системы безопасной передачи PDF Pro — механизма передачи файлов со сквозным шифрованием, при котором файлы шифруются на стороне клиента с помощью AES-256-GCM до загрузки. Сервер хранит только непрозрачный шифротекст и ни в какой момент не имеет возможности расшифровать, осмотреть или прочитать содержимое файлов. Система поддерживает два режима ключей: автоматически сгенерированный случайный ключ (передаваемый через URL-фрагмент, который никогда не отправляется на сервер) или ключ, производный от парольной фразы с использованием PBKDF2. В обоих режимах ключ шифрования существует только в браузерах отправителя и получателя. В этом документе детально описаны криптографические примитивы, поток данных, модель угроз и честно раскрытые ограничения системы. Замечание о терминологии: система не использует доказательства с нулевым разглашением (ZKP). Когда мы говорим, что сервер обладает «нулевым знанием» о ваших файлах, мы имеем в виду, что — как следствие шифрования на стороне клиента — сервер всегда хранит только шифротекст, который не может расшифровать.

1.2 Обзор архитектуры

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

Сервер намеренно спроектирован как «тупой канал» для зашифрованных данных. Он не имеет сведений о ключе шифрования, парольной фразе или содержимом файла. Это обеспечивается архитектурно, а не только политикой.

Принцип проектирования: сервер должен быть компрометируемым без компрометации пользовательских данных. Даже при полном доступе к базе данных и выполнении серверного кода злоумышленник не может расшифровать переданные файлы.

1.3 Шифрование: AES-256-GCM через Web Crypto API

Всё шифрование файлов использует алгоритм аутентифицированного шифрования AES-256-GCM, доступный через нативный Web Crypto API браузера. Это обеспечивает как конфиденциальность (данные невозможно прочитать), так и целостность (данные невозможно изменить незаметно).

1.3.1 Параметры алгоритма

ПараметрЗначениеОбоснование
АлгоритмAES-256-GCMОдобрен NIST, аутентифицированное шифрование со связанными данными (AEAD)
Размер ключа256 битМаксимальная длина ключа AES; обеспечивает 128-битный уровень защиты от перебора
Размер IV96 бит (12 байт)Рекомендованная NIST длина IV для режима GCM
Размер тега128 бит (16 байт)Полноразмерный тег аутентификации для максимальной защиты целостности
Генерация IVcrypto.getRandomValues()Криптографически стойкий генератор случайных чисел

1.3.2 Реализация шифрования

// Упрощённый поток шифрования (Web Crypto API)

const iv = crypto.getRandomValues(new Uint8Array(12));
const salt = crypto.getRandomValues(new Uint8Array(16));

// Производный ключ из парольной фразы (см. Раздел 1.4)
const key = await deriveKey(passphrase, salt);

// Шифрование файла
const ciphertext = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv: iv },
  key,
  fileArrayBuffer
);

// Пакет: [salt (16Б)] + [iv (12Б)] + [ciphertext + tag]
const blob = concatenate(salt, iv, ciphertext);

Итоговый зашифрованный blob представляет собой объединение трёх компонентов: 16-байтовой соли (используемой для деривации ключа), 12-байтового IV (используемого для AES-GCM) и шифротекста с присоединённым 16-байтовым тегом аутентификации GCM. Именно этот blob получает и хранит сервер.

1.4 Генерация и передача ключей

Безопасная передача поддерживает два взаимоисключающих режима ключей. Режим выбирается отправителем в момент создания передачи.

1.4.1 Режим A — автоматически сгенерированный ключ (по умолчанию)

В режиме по умолчанию парольная фраза не используется. Браузер напрямую генерирует криптографически случайный 256-битный ключ AES:

1.4.2 Режим B — передача с парольной фразой

Когда отправитель решает задать парольную фразу, ключ выводится из этой парольной фразы с помощью PBKDF2:

1.4.3 Параметры PBKDF2 (режим B)

ПараметрЗначениеОбоснование
АлгоритмPBKDF2Рекомендован NIST SP 800-132; широко аудируется
Хеш-функцияSHA-256Стандартный криптографический хеш; 256-битный вывод
Итерации600 000Соответствует рекомендации OWASP 2023 для PBKDF2-SHA256
Размер соли128 бит (16 байт)Уникальна для каждой передачи; предотвращает атаки по радужным таблицам
Длина выходного ключа256 битСоответствует требованию ключа AES-256

1.4.4 Реализация деривации ключа (режим B)

async function deriveKey(passphrase, salt) {
  // Импорт парольной фразы как сырого материала ключа
  const keyMaterial = await crypto.subtle.importKey(
    "raw",
    new TextEncoder().encode(passphrase),
    { name: "PBKDF2" },
    false,
    ["deriveKey"]
  );

  // Деривация ключа AES-256-GCM
  return crypto.subtle.deriveKey(
    {
      name: "PBKDF2",
      salt: salt,
      iterations: 600000,
      hash: "SHA-256"
    },
    keyMaterial,
    { name: "AES-GCM", length: 256 },
    false,
    ["encrypt", "decrypt"]
  );
}

Замечание по безопасности: в режиме B безопасность зависит от энтропии парольной фразы. Рекомендуем парольные фразы из 12+ символов, сочетающих заглавные и строчные буквы, цифры и символы.

1.5 Поток данных

Полный жизненный цикл безопасной передачи следует следующему пути:

1.5.1 Отправка (загрузка) — режим A (автоматически сгенерированный ключ)

  1. Отправитель выбирает файл в браузере.
  2. Браузер генерирует случайный 256-битный ключ AES-GCM и случайный 12-байтовый IV с помощью crypto.getRandomValues().
  3. Браузер шифрует файл с помощью AES-256-GCM, получая шифротекст и тег аутентификации.
  4. Браузер объединяет [IV | шифротекст+тег] в единый blob.
  5. Браузер загружает зашифрованный blob на сервер по HTTPS.
  6. Сервер сохраняет blob в Supabase Storage и создаёт запись метаданных (идентификатор передачи, срок действия, лимит загрузок, имя файла, размер файла).
  7. Сервер возвращает URL передачи. Браузер добавляет экспортированный ключ в URL-фрагмент (#).
  8. Отправитель делится с получателем полным URL (с фрагментом).

1.5.2 Отправка (загрузка) — режим B (парольная фраза)

  1. Отправитель выбирает файл и вводит парольную фразу в браузере.
  2. Браузер генерирует случайную 16-байтовую соль и 12-байтовый IV с помощью crypto.getRandomValues().
  3. Браузер выводит ключ AES-256 из парольной фразы с помощью PBKDF2 (600 тыс. итераций).
  4. Браузер шифрует файл с помощью AES-256-GCM, получая шифротекст и тег аутентификации.
  5. Браузер объединяет [соль | IV | шифротекст+тег] в единый blob.
  6. Браузер загружает зашифрованный blob на сервер по HTTPS.
  7. Сервер сохраняет blob в Supabase Storage и создаёт запись метаданных (идентификатор передачи, срок действия, лимит загрузок, имя файла, размер файла).
  8. Сервер возвращает URL передачи, содержащий идентификатор передачи.
  9. Отправитель передаёт URL передачи и парольную фразу получателю по разным каналам.

1.5.3 Получение (скачивание) — режим A

  1. Получатель открывает полный URL передачи (с ключом во фрагменте).
  2. Браузер извлекает ключ AES из URL-фрагмента (никогда не отправляется на сервер).
  3. Браузер скачивает зашифрованный blob с сервера по HTTPS.
  4. Браузер извлекает IV (первые 12 байт) из blob-объекта.
  5. Браузер расшифровывает шифротекст с помощью AES-256-GCM, используя извлечённые ключ и IV.
  6. Если расшифрование успешно (тег GCM валиден), пользователю предоставляется файл в открытом виде.
  7. Сервер обновляет счётчик загрузок и, если включён режим самоуничтожения после прочтения, удаляет blob.

1.5.4 Получение (скачивание) — режим B

  1. Получатель открывает URL передачи и вводит парольную фразу в браузере.
  2. Браузер скачивает зашифрованный blob с сервера по HTTPS.
  3. Браузер извлекает соль (первые 16 байт) и IV (следующие 12 байт) из blob-объекта.
  4. Браузер выводит ключ AES-256 из парольной фразы и соли с помощью PBKDF2 (600 тыс. итераций).
  5. Браузер расшифровывает шифротекст с помощью AES-256-GCM, используя производный ключ и IV.
  6. Если расшифрование успешно (тег GCM валиден), пользователю предоставляется файл в открытом виде.
  7. Если расшифрование не удалось (неверная парольная фраза = неверный ключ = невалидный тег GCM), показывается ошибка.
  8. Сервер обновляет счётчик загрузок и, если включён режим самоуничтожения после прочтения, удаляет blob.

1.6 Что хранит сервер и что он никогда не видит

Элемент данныхСервер имеет доступ?Подробности
Зашифрованный blob (соль + IV + шифротекст + тег)ДаНепрозрачные двоичные данные; сервер не может интерпретировать содержимое
Идентификатор передачиДаИдентификаторы передачи — это значения UUID v4, генерируемые функцией PostgreSQL gen_random_uuid(), что обеспечивает 122 бита криптографической случайности из CSPRNG сервера
Исходное имя файлаДаХранится в метаданных для отображения получателю
Исходный размер файлаДаХранится в метаданных для отображения
Метка времени истеченияДаИспользуется для автоудаления
Счётчик / лимит загрузокДаИспользуется для самоуничтожения после прочтения и применения лимита загрузок
Идентификатор отправителя (если авторизован)ДаПривязывает передачу к учётной записи для управления
Парольная фразаНет — никогдаНикогда не отправляется на сервер; никогда не покидает браузер
Производный ключ шифрованияНет — никогдаСуществует только в памяти браузера во время шифрования/расшифрования
Содержимое файла в открытом видеНет — никогдаДо сервера доходит только зашифрованный шифротекст
Количество итераций PBKDF2НетЖёстко задано в клиенте; не передаётся на сервер

1.7 Автоматическое истечение и сжигание после прочтения

Все безопасные передачи эфемерны по своему замыслу. Опция постоянного хранения отсутствует.

1.7.1 Параметры срока действия

ОпцияПоведениеПрименение
Самоуничтожение после прочтенияЗашифрованный blob удаляется сразу после первой успешной загрузкиНа стороне сервера: blob удаляется из хранилища после завершения потока загрузки
1 часАвтоудаление через 1 час независимо от статуса загрузокНа стороне сервера: запланированная задача очистки + проверка истечения при доступе
24 часаАвтоудаление через 24 часаТак же, как выше
7 днейМаксимальный срок хранения; автоудаление через 7 днейТак же, как выше

1.7.2 Гарантия удаления

Когда передача истекает или уничтожается после прочтения, зашифрованный blob окончательно удаляется из Supabase Storage. Запись метаданных сохраняется в течение 30 дней в состоянии «мягкого удаления» (для расследования злоупотреблений), после чего окончательно удаляется. Запись метаданных не содержит ключа шифрования, парольной фразы или какой-либо информации, которую можно было бы использовать для восстановления файла.

1.8 Модель угроз и меры защиты

УгрозаВектор атакиМеры защиты
Компрометация сервера Злоумышленник получает полный доступ к базе данных и хранилищу Все сохранённые данные — это шифротекст AES-256-GCM. Злоумышленник получает только непрозрачные blob-объекты. Без парольной фразы перебор 256-битного AES вычислительно невозможен.
Перехват в сети (MITM) Злоумышленник перехватывает данные при передаче Весь трафик использует TLS 1.3. Даже если TLS будет взломан, злоумышленник получит только зашифрованные blob-объекты (то же, что и при компрометации сервера).
Слабая парольная фраза Злоумышленник подбирает короткую или распространённую парольную фразу PBKDF2 с 600 тыс. итераций делает каждую попытку вычислительно затратной. Парольная фраза из 4 символов всё равно потребует значительных вычислений. Интерфейс применяет минимальную длину парольной фразы и показывает индикатор её надёжности.
Перехват парольной фразы Злоумышленник перехватывает парольную фразу, передаваемую между отправителем и получателем Парольная фраза передаётся внеполосно (не через нашу систему). Рекомендуем передавать её через канал, отличный от URL передачи. Это ответственность пользователя.
Подмена клиентского кода Злоумышленник изменяет JavaScript, доставляемый пользователю Все ресурсы доставляются по HTTPS через CDN Vercel. Хеши Subresource Integrity (SRI) защищают от подмены на уровне CDN. Пользователи могут проверить исходный код в DevTools браузера.
Извлечение из памяти Злоумышленник извлекает ключ шифрования из памяти браузера Ключи Web Crypto API помечаются как неизвлекаемые там, где это возможно. Производные ключи существуют в памяти только во время операции шифрования/расшифрования. Изоляция памяти браузера обеспечивает защиту на уровне ОС.
Атака повторного воспроизведения Злоумышленник повторно использует перехваченный зашифрованный blob Каждая передача имеет уникальный идентификатор и защищена лимитами загрузок и сроком действия. Передачи с самоуничтожением после прочтения удаляются после первого доступа.

1.8.1 Допущения

1.8.2 Вне области действия

1.9 Ограничения и честное раскрытие

Честные ограничения: ни одна система безопасности не идеальна. Мы за прозрачное раскрытие известных ограничений.


Privacy-First Cryptographic Document подписание

PDF Pro Whitepaper WP-002 — Архитектура and Безопасность

2.1 Аннотация

В этом техническом документе описана архитектура системы приватной подписи от PDF Pro — механизма криптографической подписи документов, при котором PDF-документ никогда не покидает браузер подписанта. Система использует ECDSA с кривой P-256 и хеширование SHA-256 для создания отделённых цифровых подписей. На сервер передаются только хеш документа, криптографическая подпись и публичный ключ. Приватные ключи генерируются, шифруются и хранятся исключительно в браузере пользователя в IndexedDB, защищённом деривацией ключа PBKDF2 (600 000 итераций) и шифрованием AES-256-GCM. В этом документе детально описаны полная архитектура подписания и проверки, модель управления ключами, схема подписанной полезной нагрузки, дизайн аудиторского следа, модель угроз и честно раскрытые ограничения.

2.2 Обзор архитектуры

Система приватной подписи спроектирована вокруг фундаментального ограничения: PDF-документ никогда не должен передаваться на сервер. Это обеспечивается архитектурно через модель отделённой подписи.

Основная гарантия: сервер никогда не видит, не получает и не обрабатывает PDF-документ. Единственные связанные с документом данные, которые сервер когда-либо получает, — это хеш SHA-256 — значение фиксированного размера в 256 бит, из которого исходный документ восстановить невозможно.

2.3 подписание Algorithm: ECDSA P-256 / SHA-256

2.3.1 Параметры алгоритма

ПараметрЗначениеОбоснование
Алгоритм подписиECDSA (алгоритм цифровой подписи на эллиптических кривых)NIST FIPS 186-4; компактные подписи; высокая безопасность на бит ключа
КриваяP-256 (secp256r1 / prime256v1)Одобрена NIST; 128-битный уровень безопасности; широкая поддержка в Web Crypto API
Хеш-функцияSHA-256NIST FIPS 180-4; 256-битный дайджест; устойчива к коллизиям
Размер ключа256-битный приватный ключ, 512-битный публичный ключ (несжатый)Стандарт для P-256; эквивалентно ~3072-битному RSA
Размер подписи64 байта (r: 32 байта, s: 32 байта)Компактный; подходит для хранения и передачи
Формат подписиIEEE P1363 (сырое r || s)Нативный вывод Web Crypto API; для хранения кодируется в base64url

Кодирование подписи: ECDSA с P-256 в Web Crypto API создаёт сырую 64-байтовую подпись, состоящую из двух 32-байтовых целых чисел (r || s) в формате big-endian фиксированной ширины. Этот сырой вывод кодируется в base64url для хранения. Это НЕ DER-кодирование — это формат IEEE P1363, который Web Crypto API создаёт нативно.

2.3.2 Поток подписания

// 1. Хеширование PDF-документа (на стороне клиента)
const fileBuffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest("SHA-256", fileBuffer);
const hashHex = Array.from(new Uint8Array(hashBuffer))
  .map(b => b.toString(16).padStart(2, '0')).join('');

// 2. Подписание хеша приватным ключом (на стороне клиента)
const signature = await crypto.subtle.sign(
  { name: "ECDSA", hash: "SHA-256" },
  privateKey,   // CryptoKey из IndexedDB (расшифрованный)
  hashBuffer
);

// 3. Отправка на сервер: хеш + подпись + публичный ключ (НЕ сам PDF)
await submitSignature({
  documentHash: hashHex,
  signature: base64Encode(signature),
  publicKey: exportedPublicKeyJWK
});

2.4 Управление ключами: эфемерные и постоянные

Тип ключаКонтекстЖизненный циклХранение
Эфемерный Гостевые пользователи (не вошедшие в систему) Генерируется на каждую сессию; уничтожается при закрытии вкладки Только в памяти (объект CryptoKey); никогда не сохраняется
Постоянный Авторизованные пользователи (вошедшие в систему) Генерируется один раз; сохраняется между сессиями; может быть отозван IndexedDB (зашифрован с помощью PBKDF2 + AES-256-GCM)

2.4.1 Генерация ключа

// Генерация пары ключей ECDSA P-256 (Web Crypto API)
const keyPair = await crypto.subtle.generateKey(
  {
    name: "ECDSA",
    namedCurve: "P-256"
  },
  true,   // extractable (нужно для шифрования + хранения)
  ["sign", "verify"]
);

// Экспорт публичного ключа в формате JWK для регистрации на сервере
const publicKeyJWK = await crypto.subtle.exportKey("jwk", keyPair.publicKey);

// Экспорт приватного ключа в формате JWK для зашифрованного хранения
const privateKeyJWK = await crypto.subtle.exportKey("jwk", keyPair.privateKey);

Формат публичного ключа: публичные ключи экспортируются и хранятся в формате JWK (JSON Web Key). Отпечаток ключа вычисляется как SHA-256 от канонического JWK, содержащего только публичные поля {crv, kty, x, y} с ключами, отсортированными по алфавиту.

2.5 Защита приватного ключа: PBKDF2 + AES-GCM → IndexedDB

Постоянные приватные ключи никогда не хранятся в открытом виде. Перед записью в IndexedDB приватный ключ (экспортированный в виде JWK JSON) шифруется по той же схеме, что и в системе безопасной передачи:

2.5.1 Параметры защиты

ПараметрЗначение
Деривация ключаPBKDF2-SHA256, 600 000 итераций
СольСлучайные 16 байт (на каждый ключ)
ШифрованиеAES-256-GCM
IVСлучайные 12 байт (на каждое шифрование)
ВходJWK приватного ключа (JSON-строка в UTF-8)
Выход, сохраняемый в IndexedDB{ salt, iv, ciphertext, publicKeyJWK, keyId, createdAt }

2.5.2 Схема хранения

// Структура записи IndexedDB для зашифрованного ключа подписи
{
  "keyId":       "uuid-v4-unique-identifier",
  "publicKey":   { /* формат JWK, незашифрованный */ },
  "encryptedPrivateKey": {
    "salt":       "base64-encoded-16-bytes",
    "iv":         "base64-encoded-12-bytes",
    "ciphertext": "base64-encoded-aes-gcm-ciphertext"
  },
  "algorithm":   "ECDSA",
  "curve":       "P-256",
  "createdAt":   "2026-04-16T00:00:00.000Z",
  "userId":      "supabase-auth-user-id"
}

Восстановление ключа: если пользователь забывает свою парольную фразу подписи, приватный ключ восстановить невозможно. У нас нет парольной фразы, производного ключа или какого-либо механизма обхода защиты PBKDF2 + AES-GCM. Пользователям следует экспортировать резервные копии ключей.

2.6 Модель отделённой подписи

PDF Pro использует модель отделённой подписи, что означает, что подпись хранится отдельно от документа. Это ключевой механизм конфиденциальности: документ никогда не покидает устройство подписанта.

2.6.1 Что отправляется на сервер

2.6.2 Что НЕ отправляется на сервер

Криптографическая гарантия: SHA-256 — это односторонняя хеш-функция. Имея только хеш e3b0c44298fc1c14..., она обеспечивает сильную криптографическую гарантию (при условиях безопасности ECDSA и SHA-256), что исходный документ не может быть восстановлен. Хеш не раскрывает ничего о содержимом, длине или структуре документа, кроме подтверждения идентичности при повторном хешировании.

2.7 подписан Payload Schema v1.0

Следующая JSON-схема определяет полную запись подписи, хранимую на сервере:

{
  "schemaVersion":  "1.0",
  "signatureId":    "uuid-v4",
  "documentHash":   "sha256-hex-64-chars",
  "hashAlgorithm":  "SHA-256",
  "signature":      "base64-encoded-ecdsa-signature",
  "signatureAlgorithm": "ECDSA",
  "curve":          "P-256",
  "publicKey": {
    "kty": "EC",
    "crv": "P-256",
    "x":   "base64url-encoded-x-coordinate",
    "y":   "base64url-encoded-y-coordinate"
  },
  "signer": {
    "identityLevel": "authenticated | self-asserted",
    "displayName":   "string or null",
    "email":         "string or null",
    "userId":        "supabase-uid or null"
  },
  "timestamp":      "ISO-8601-UTC",
  "metadata": {
    "fileName":     "original-file-name.pdf",
    "fileSize":     123456,
    "pageCount":    12,
    "clientVersion": "2.0.0",
    "userAgent":    "browser-user-agent-string"
  },
  "auditChain": {
    "previousEventHash": "sha256-of-previous-audit-event or null",
    "eventHash":         "sha256-of-this-record"
  }
}

2.8 Поток проверки

Проверка подписи — двухэтапный процесс: криптографическая проверка на стороне клиента с последующей серверной перекрёстной сверкой.

2.8.1 Этап 1: криптографическая проверка на стороне клиента

  1. Пользователь загружает PDF в браузер.
  2. Браузер вычисляет хеш SHA-256 загруженного PDF.
  3. Браузер запрашивает у сервера любые записи подписей, соответствующие этому хешу.
  4. Для каждой возвращённой записи подписи браузер выполняет проверку ECDSA:
    const isValid = await crypto.subtle.verify(
      { name: "ECDSA", hash: "SHA-256" },
      importedPublicKey,
      signatureBuffer,
      hashBuffer
    );
  5. Если isValid === true, подпись криптографически действительна: документ не был изменён с момента подписания, и подпись создана владельцем соответствующего приватного ключа.

2.8.2 Этап 2: серверная перекрёстная сверка

  1. Сервер подтверждает, что публичный ключ в записи подписи зарегистрирован за известным пользователем (для авторизованных подписей).
  2. Сервер подтверждает, что запись подписи не была отозвана.
  3. Сервер подтверждает целостность аудиторского следа (валидация хеш-цепочки).
  4. Сервер возвращает уровень идентификации подписанта и статус регистрации.

2.8.3 Результаты проверки

РезультатЗначение
Действительна (авторизована)Подпись криптографически действительна И публичный ключ принадлежит зарегистрированному, авторизованному пользователю PDF Pro.
Действительна (самозаявлена)Подпись криптографически действительна, но идентичность подписанта самозаявлена (гостевой пользователь или непроверенное имя).
НедействительнаКриптографическая проверка не пройдена. Документ был изменён после подписания или подпись повреждена.
ОтозванаПодпись была действительной, но была явно отозвана подписантом.
Подпись не найденаЗапись подписи для этого хеша документа не существует.

2.9 Аудиторский след: события, связанные хешами

Каждое событие подписания и проверки регистрируется в аудиторском следе с защитой от подделки. События связаны хеш-цепочкой: каждое событие содержит хеш SHA-256 предыдущего события, образуя цепочку только для добавления, аналогичную блокчейну.

2.9.1 Типы событий аудита

Тип событияТриггерЗаписываемые данные
KEY_REGISTEREDПользователь регистрирует новый публичный ключJWK публичного ключа, идентификатор пользователя, метка времени
DOCUMENT_SIGNEDПользователь подписывает документХеш документа, подпись, публичный ключ, идентичность подписанта, метка времени
SIGNATURE_VERIFIEDЛюбой пользователь проверяет подписьХеш документа, результат проверки, информация о проверяющем (если авторизован), метка времени
SIGNATURE_REVOKEDПодписант отзывает подписьИдентификатор подписи, причина отзыва, метка времени
KEY_REVOKEDПользователь отзывает публичный ключИдентификатор публичного ключа, причина отзыва, метка времени

2.9.2 Структура хеш-цепочки

// Каждое событие аудита включает:
{
  "eventId":            "uuid-v4",
  "eventType":          "DOCUMENT_SIGNED",
  "timestamp":          "ISO-8601-UTC",
  "data":               { /* полезная нагрузка, специфичная для события */ },
  "previousEventHash": "sha256-of-previous-event-json",
  "eventHash":          "sha256-of-this-event-json-without-eventHash"
}

// Обнаружение подделки: для проверки цепочки вычислите:
// SHA-256(JSON.stringify(событие без поля eventHash))
// и убедитесь, что значение совпадает с eventHash.
// Затем убедитесь, что previousEventHash совпадает с eventHash предыдущего события.

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

Важное ограничение: хеш-цепочка делает подделку обнаруживаемой в пределах зарегистрированной последовательности событий. Однако администратор базы данных с прямым доступом теоретически мог бы удалить и перестроить цепочку. Более сильные гарантии потребовали бы внешней метки времени или подтверждения третьей стороной, что в этой версии не реализовано.

2.10 Уровни идентификации

УровеньТребованияСвойства доверияСценарий использования
Авторизованный Вошедший в систему пользователь PDF Pro с проверенным email; постоянная пара ключей, зарегистрированная за учётной записью Email подтверждён через Supabase Auth; публичный ключ привязан к авторизованной учётной записи; аудиторский след связан с идентификатором пользователя Деловые документы, договоры, формальные соглашения
Самозаявленный Гостевой пользователь или авторизованный пользователь с самостоятельно введённым именем; эфемерная или постоянная пара ключей Криптографическая целостность гарантирована; идентичность подписанта самозаявлена и независимо не проверена Быстрое подписание, личные документы, неформальные соглашения

Замечание: в интерфейсе продукта «self_asserted» может отображаться как «Самозаявленная идентичность» или «Гостевое подписание». «authenticated» может отображаться как «Авторизованный аккаунт». Это отображаемые метки для одних и тех же базовых уровней идентификации.

Привязка идентичности: «авторизованная» подпись означает, что публичный ключ зарегистрирован за учётной записью PDF Pro с проверенным email. Это НЕ означает, что реальная идентичность подписанта проверена через государственный документ, биометрию или личную верификацию. Мы не выполняем проверки KYC (Know Your Customer).

2.11 Модель угроз

УгрозаВектор атакиМеры защиты
Атака повторного воспроизведения Злоумышленник копирует действительную подпись и применяет её к другому документу Подпись привязана к SHA-256 хешу конкретного документа. У другого документа будет другой хеш, и проверка ECDSA не пройдёт.
Подделка Злоумышленник создаёт действительную подпись без приватного ключа Безопасность ECDSA P-256 основана на проблеме дискретного логарифма на эллиптических кривых (ECDLP). Подделка подписи без приватного ключа вычислительно невозможна (128-битный уровень безопасности).
Подмена ключа Злоумышленник регистрирует свой публичный ключ и заявляет, что подпись поставлена кем-то другим Авторизованные подписи привязывают публичный ключ к проверенному email. Аудиторский след фиксирует, какой ключ подписал какой документ. События регистрации ключей связаны хеш-цепочкой.
Подмена документа Злоумышленник изменяет подписанный PDF и заявляет, что подпись остаётся действительной Любое изменение PDF меняет его SHA-256 хеш. Существующая подпись не пройдёт проверку по новому хешу. Поиск коллизии (другой документ с тем же хешем) требует ~2^128 операций.
Кража приватного ключа Злоумышленник извлекает зашифрованный приватный ключ из IndexedDB Приватный ключ зашифрован с помощью AES-256-GCM на ключе, полученном через PBKDF2 (600K итераций). Без парольной фразы расшифровать ключ вычислительно невозможно.
Компрометация сервера Злоумышленник получает полный доступ к серверу На сервере находятся только публичные ключи и записи подписей. Приватные ключи никогда не достигают сервера. Злоумышленник не может подделывать новые подписи. Он может удалить или изменить существующие записи, но разрывы хеш-цепочки будут обнаружены.
Подделка аудиторского следа Злоумышленник изменяет события аудиторского следа на сервере События связаны хеш-цепочкой: изменение любого события разрывает цепочку, начиная с этой точки. Независимые средства проверки могут обнаружить разрывы цепочки.

2.11.1 Допущения

2.11.2 Вне области действия

2.12 Честное раскрытие

Чем подписи PDF Pro НЕ являются:

2.12.1 Для чего подписи PDF Pro ПОДХОДЯТ

Наше обязательство: мы строим безопасность через архитектуру, а не через маркетинг. Эти технические документы описывают, как именно работают наши системы, включая их ограничения. Мы считаем, что заботящиеся о безопасности пользователи заслуживают полной технической прозрачности. Если у вас есть вопросы по какому-либо аспекту нашей архитектуры, свяжитесь с нами по адресу info@webdesign9.com.