Хранение ключей и меры безопасности

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

PEM (Privacy-Enhanced Mail) Текстовый формат, кодированный Base64 и обрамлённый служебными заголовками:

-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----

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

  • удобство хранения и передачи
  • читаемость Недостатки:
  • повышенный риск утечки при неосторожном обращении

DER (Distinguished Encoding Rules) Бинарный формат ASN.1:

  • более компактный
  • сложнее для анализа человеком
  • используется при работе с сертификатами и низкоуровневыми API

JWK (JSON Web Key) JSON-структура:

{
  "kty": "RSA",
  "n": "...",
  "e": "AQAB",
  "d": "..."
}

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

  • нативная интеграция с JavaScript
  • удобство передачи через API Недостатки:
  • требует строгого контроля доступа

Загрузка и инициализация ключей в Jsrsasign

Основной класс для работы с ключами — KEYUTIL.

Загрузка приватного ключа из PEM:

const key = KEYUTIL.getKey(pemString);

Загрузка с паролем:

const key = KEYUTIL.getKey(pemEncrypted, "password");

Работа с JWK:

const key = KEYUTIL.getKey(jwkObject);

Особенность: библиотека автоматически определяет формат ключа, что упрощает интеграцию, но увеличивает требования к валидации входных данных.


Шифрование приватных ключей

Хранение приватного ключа в незашифрованном виде — критическая уязвимость.

Jsrsasign поддерживает экспорт зашифрованных ключей:

const pemEncrypted = KEYUTIL.getPEM(privateKey, "PKCS8PRV", "password");

Под капотом используются алгоритмы:

  • AES
  • Triple DES
  • PBKDF2 для генерации ключа из пароля

Ключевые параметры безопасности:

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

Безопасное хранение в браузере

В клиентских приложениях ключи особенно уязвимы.

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

  • хранение в localStorage
  • хранение в sessionStorage
  • встраивание в исходный код

Допустимые практики:

  1. Web Crypto API + IndexedDB

    • ключи генерируются внутри браузера
    • приватный ключ не покидает защищённый контекст
  2. Memory-only хранение

    • ключ существует только в оперативной памяти
    • удаляется при перезагрузке страницы
  3. Использование аппаратных средств

    • WebAuthn
    • токены безопасности

Безопасное хранение на сервере

На стороне сервера применяются другие стратегии:

Файловая система:

  • доступ только для системного пользователя
  • права: 600
  • изоляция в контейнерах

HSM (Hardware Security Module):

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

KMS (Key Management Service):

  • централизованное управление ключами
  • автоматическая ротация

Ротация ключей

Регулярная смена ключей снижает риск компрометации.

Подходы:

  • версия ключа (kid в JWK)
  • поддержка нескольких активных ключей
  • плавная замена без остановки системы

Пример структуры:

{
  "keys": [
    { "kid": "key1", ... },
    { "kid": "key2", ... }
  ]
}

Контроль доступа

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

Принципы:

  • least privilege
  • разделение ролей
  • аудит операций

Практика:

  • разные ключи для подписи и шифрования
  • ограничение IP или сервисов
  • журналирование использования

Защита от утечек

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

  1. Логи

    • случайный вывод ключа в консоль
    • логирование PEM-строк
  2. Снимки памяти

    • дампы процессов
    • отладка
  3. Сетевой трафик

    • передача без TLS
    • MITM-атаки

Меры защиты:

  • маскирование данных
  • отключение debug-режимов
  • обязательный HTTPS

Очистка ключей из памяти

После использования ключи должны удаляться:

key = null;

Дополнительно:

  • перезапись буферов
  • минимизация времени жизни объекта

В JavaScript это ограничено сборщиком мусора, поэтому важно:

  • не сохранять ссылки
  • избегать глобальных переменных

Проверка целостности ключей

Перед использованием ключ необходимо валидировать:

KEYUTIL.getKey(pem);

Ошибки парсинга:

  • повреждение структуры
  • подмена данных
  • некорректный формат

Дополнительно:

  • проверка длины ключа
  • проверка алгоритма

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

Пароль для шифрования ключа должен соответствовать требованиям:

  • длина не менее 12 символов
  • случайность
  • отсутствие повторного использования

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

  • генерация через криптографический RNG
  • хранение в менеджерах секретов

Интеграция с системами секретов

Современные архитектуры используют:

  • HashiCorp Vault
  • AWS Secrets Manager
  • Azure Key Vault

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

  • централизованное хранение
  • контроль доступа
  • аудит

Защита от атак на стороне клиента

В браузере ключи подвержены:

  • XSS-атакам
  • внедрению скриптов
  • расширениям браузера

Меры:

  • CSP (Content Security Policy)
  • sandbox iframe
  • минимизация сторонних библиотек

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

Рекомендации:

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

Антипаттерны:

const privateKey = "-----BEGIN PRIVATE KEY-----...";
localStorage.setItem("key", pem);

Разделение ключей по назначению

Необходимо использовать разные ключи для:

  • подписи (JWT, JWS)
  • шифрования (JWE)
  • TLS

Это снижает риск компрометации всей системы при утечке одного ключа.


Метаданные ключей

При работе с JWK важно учитывать поля:

  • kid — идентификатор
  • alg — алгоритм
  • use — назначение

Пример:

{
  "kty": "RSA",
  "kid": "signing-key",
  "use": "sig",
  "alg": "RS256"
}

Обновление и отзыв ключей

При компрометации:

  1. Немедленный отзыв
  2. Удаление из доверенных
  3. Генерация нового ключа
  4. Уведомление зависимых систем

Логирование и аудит

Фиксируются:

  • операции подписи
  • ошибки
  • попытки доступа

Не фиксируются:

  • сами ключи
  • пароли

Итерации PBKDF2 и защита паролей

При шифровании ключей:

  • минимум 10000 итераций
  • лучше 100000+
  • использование соли

Это усложняет перебор пароля.


Минимизация поверхности атаки

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

Управление жизненным циклом ключей

Этапы:

  1. Генерация
  2. Распространение
  3. Использование
  4. Ротация
  5. Удаление

Каждый этап требует контроля и логирования.


Совместимость и миграции

При смене формата:

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

Проверка алгоритмов

Недопустимо использование устаревших алгоритмов:

  • MD5
  • SHA1
  • слабые RSA (менее 2048 бит)

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

  • RSA 2048+
  • ECDSA
  • SHA-256 и выше