Отладка несовпадения ключей

В Iron ключ играет центральную роль в процессе «запечатывания» (seal) и «распечатывания» (unseal) данных. Любое несоответствие между ключами приводит к невозможности расшифровки полезной нагрузки, что выражается в ошибках валидации или криптографической проверки.

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

Как формируется ключ в Iron

В библиотеке используется строковый секрет, который преобразуется в набор криптографических ключей через KDF (key derivation function). Даже минимальное изменение строки секрета приводит к полностью другим производным значениям.

Типичная схема выглядит следующим образом:

  • входной secret (строка)
  • salt (может быть фиксированным или заданным)
  • iterations (количество итераций PBKDF2)
  • алгоритм хеширования (обычно sha256)

Из этого формируется:

  • encryption key
  • integrity key

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

Типовые причины несовпадения ключей

Различие в исходном secret

Даже незначительные изменения приводят к полной несовместимости:

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

Пример:

const secret = "my-secret";
const secretFromEnv = process.env.SECRET; // "my-secret "

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

Несовпадение параметров Iron

Iron позволяет настраивать параметры шифрования. Если при seal и unseal используются разные настройки, возникает ошибка.

Критически важные параметры:

  • encryption
  • integrity
  • ttl
  • timestampSkewSec

Различие даже одного параметра приводит к невозможности валидации.

Ошибка несовпадения ключа при unseal

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

Внутренне процесс проходит несколько этапов:

  1. извлечение метаданных
  2. восстановление salt и iv
  3. генерация ключей из secret
  4. проверка HMAC
  5. расшифровка payload

Сбой на любом этапе чаще всего связан с несоответствием ключа или параметров KDF.

Проблема окружений (development vs production)

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

Типичный сценарий:

  • локально используется .env
  • на сервере используется секрет из CI/CD
  • staging имеет отдельный secret

Если объект был создан в одном окружении и проверяется в другом — расшифровка невозможна.

Ошибки сериализации секрета

Иногда secret хранится в виде JSON или с дополнительными символами:

{
  "SECRET": "\"my-secret\""
}

В результате фактическое значение включает кавычки, что приводит к несовпадению ключа.

Влияние алгоритма и версии Iron

Разные версии библиотеки могут по-разному обрабатывать:

  • дефолтный salt
  • алгоритмы хеширования
  • форматирование payload

Если данные были зашифрованы старой версией, а расшифровка выполняется новой (или наоборот), возможно несовпадение даже при одинаковом secret.

Диагностика ключевых расхождений

Проверка стабильности secret

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

console.log(JSON.stringify(secret));
console.log(JSON.stringify(process.env.SECRET));

Цель — выявить скрытые символы.

Проверка длины и байтов

console.log(Buffer.from(secret).length);
console.log(Buffer.from(process.env.SECRET).length);

Разница указывает на наличие невидимых символов.

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

import Iron from '@hapi/iron';

const secret = process.env.IRON_SECRET;

const data = {
  userId: 123,
  role: "admin"
};

const sealed = await Iron.seal(data, secret, Iron.defaults);

const unsealed = await Iron.unseal(sealed, secret, Iron.defaults);

Ключевое требование: secret должен быть идентичен в обоих вызовах.

Несовпадение из-за конфигурации defaults

Объект Iron.defaults содержит параметры:

  • encryption
  • integrity
  • ttl
  • timestampSkewSec

Если при seal используется кастомная конфигурация, а при unseal дефолтная, возникает ошибка.

Пример расхождения:

const optionsSeal = {
  ...Iron.defaults,
  ttl: 5000
};

const optionsUnseal = {
  ...Iron.defaults,
  ttl: 10000
};

Даже если secret одинаковый, результат проверки будет отрицательным.

Проблемы с кодировкой

При передаче секрета через разные источники возможны различия:

  • UTF-8
  • Base64
  • URL encoding

Если secret декодируется дважды или не декодируется вовсе, ключ становится несовместимым.

Пример ошибки:

const secret = Buffer.from(process.env.SECRET, 'base64').toString('utf8');

Если значение уже в UTF-8, происходит искажение.

Влияние временных параметров

Некоторые конфигурации Iron учитывают TTL и допустимое отклонение времени.

Если:

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

возможна ошибка, интерпретируемая как проблема ключа.

Стратегия локализации проблемы

Разбор несовпадения ключей обычно проводится поэтапно:

  1. сравнение secret побайтно
  2. проверка одинаковости конфигураций
  3. исключение различий версий Iron
  4. проверка окружения выполнения
  5. анализ кодировки входных данных

Скрытые ошибки в CI/CD

Часто проблема возникает при автоматическом деплое:

  • secret передаётся через pipeline variables
  • переменная обрезается
  • добавляются кавычки
  • используется base64 без декодирования

В результате production и development расходятся на уровне ключа, хотя конфигурационно выглядят идентичными.

Поведение при частичном совпадении параметров

Важно учитывать, что Iron не допускает частичной деградации безопасности. Даже если:

  • encryption совпадает
  • integrity совпадает
  • payload валиден

но secret отличается — проверка всегда завершается ошибкой без возможности восстановления данных.

Итоговая модель причины ошибки

Несовпадение ключей всегда сводится к одному из факторов:

  • различие исходного secret
  • различие параметров KDF
  • различие версии библиотеки
  • различие кодировки
  • различие окружения выполнения

Криптографическая модель Iron не предполагает «приблизительных совпадений», поэтому даже минимальное отклонение делает данные полностью недействительными.