Логирование криптографических ошибок без утечки данных

В криптографических системах на базе библиотеки jose ошибки возникают не только из-за программных дефектов, но и как часть ожидаемой модели угроз: неверная подпись, истёкший токен, несовпадение алгоритма, повреждённый JWT или попытка использования ключа не того типа.

Ключевой парадокс заключается в том, что такие ошибки одновременно:

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

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

Особенности ошибок в jose и их семантика

Библиотека jose строго разделяет типы криптографических операций:

  • JWS (подпись)
  • JWE (шифрование)
  • JWT (структурная надстройка)
  • ключи (JWK, PEM, raw key material)

Каждый из этих уровней генерирует ошибки, которые могут содержать чувствительные данные в необработанном виде.

Типичные классы ошибок:

  • JOSEError
  • JWSInvalid
  • JWSSignatureVerificationFailed
  • JWEInvalid
  • JWTClaimValidationFailed

Внутри сообщения ошибки может оказаться:

  • фрагмент токена
  • алгоритм подписи
  • идентификатор ключа (kid)
  • описание несоответствия структуры

Прямое логирование этих данных без фильтрации создаёт риск компрометации системы.

Принципы безопасного логирования

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

Основные принципы:

1. Исключение токенов из логов

JWT, JWS и JWE не должны попадать в лог даже частично. Любая их часть может содержать полезную информацию для злоумышленника.

2. Запрет на логирование ключей

Ни приватные, ни публичные ключи, ни их производные (fingerprint в сыром виде) не должны записываться в журнал.

3. Стабильная форма ошибок

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

4. Контролируемая детализация

Разделение уровней логирования:

  • error: только тип сбоя
  • debug: метаданные без криптографического контента
  • trace: запрещён для production

Опасные паттерны логирования

Наиболее распространённые ошибки при работе с jose связаны с избыточной детализацией:

Логирование объекта ошибки целиком

catch (err) {
  console.error(err);
}

Такая практика может вывести внутренние поля библиотеки, включая цепочки валидации токена.

Логирование JWT или его частей

console.log(token);

или даже:

console.log(token.split('.')[1]);

Base64-декодированная часть payload может содержать персональные данные или claims, которые нельзя раскрывать.

Логирование ключей

console.log(privateKey);

Даже в сериализованной форме это критическая утечка.

Безопасная модель обработки ошибок jose

Корректная стратегия заключается в нормализации ошибки до безопасного формата до записи в лог.

Пример безопасного обработчика

import { JOSEError } from 'jose';

function sanitizeJoseError(err) {
  if (err instanceof JOSEError) {
    return {
      type: 'JOSEError',
      code: err.code || 'unknown_jose_error'
    };
  }

  return {
    type: 'UnknownError',
    code: 'unexpected_error'
  };
}

В этом подходе:

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

Разделение уровней контекста

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

Допустимые поля

  • имя операции (verify, sign, decrypt)
  • идентификатор запроса (requestId)
  • тип алгоритма (если не является секретом)
  • статус проверки

Недопустимые поля

  • токены (JWT/JWS/JWE)
  • ключи
  • payload claims с пользовательскими данными
  • заголовки с sensitive metadata

Нормализация ошибок при валидации JWT

При работе с JWT в jose часто используется валидация:

  • срока действия
  • аудитории
  • issuer
  • алгоритма подписи

Ошибка на этом уровне должна быть приведена к унифицированному виду:

try {
  await jwtVerify(token, key, {
    issuer: 'auth-service',
    audience: 'api'
  });
} catch (err) {
  logger.error({
    event: 'jwt_verification_failed',
    reason: mapJoseError(err)
  });
}

Функция mapJoseError должна исключать любые внутренние детали библиотеки.

Защита от логирования через исключения

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

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

  • перехват исключения
  • преобразование в DTO
  • логирование только DTO

Это предотвращает случайное раскрытие структуры ошибки.

Маскирование чувствительных данных

Если бизнес-логика требует логировать часть контекста, применяется маскирование:

  • токены заменяются на хеш
  • ключи — на fingerprint
  • payload — полностью исключается

Пример:

function maskToken(token) {
  return `token:${crypto.createHash('sha256').update(token).digest('hex').slice(0, 8)}`;
}

Даже при этом оригинальный токен не должен сохраняться в памяти логов.

Поведение в production-среде

В продакшене библиотека jose должна работать в режиме:

  • минимальной детализации ошибок
  • отключённого debug-логирования
  • централизованной обработки исключений

Любая утечка через лог-файлы рассматривается как уязвимость уровня информации о внутреннем устройстве системы.

Централизация обработки ошибок

Архитектурно правильный подход предполагает единый слой обработки криптографических ошибок:

  • middleware (в HTTP сервисах)
  • interceptor (в RPC)
  • wrapper над jose вызовами

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

Разграничение ответственности логгера

Логгер не должен знать о содержимом криптографии. Его задача — фиксировать факт события, а не его содержимое.

Пример правильного разделения:

  • jose слой: выполняет криптографию
  • сервисный слой: интерпретирует результат
  • логгер: записывает нормализованное событие

Проверка логов на утечки

При использовании jose в высоконагруженных системах необходимо регулярно проводить аудит логов:

  • поиск JWT-паттернов
  • поиск base64 блоков
  • поиск PEM структур
  • анализ stack trace на наличие секретов

Любое совпадение считается потенциальной утечкой и требует переработки слоя логирования.