В Iron механизм ротации ключей строится вокруг идеи множественных паролей, где активный ключ используется для шифрования новых данных, а все предыдущие сохраняются для расшифровки уже выданных токенов. Такой подход позволяет обновлять криптографические секреты без принудительного разрыва сессий и без необходимости отзывать уже выданные токены.
В основе Iron лежит список секретов (password array). Поведение библиотеки при этом предсказуемо:
При изменении ключей старая информация не становится недоступной, пока её ключ присутствует в списке.
import Iron from '@hapi/iron';
const passwords = [
'newest-secret-key',
'previous-secret-key',
'legacy-secret-key'
];
Любой токен, созданный с использованием одного из этих ключей, остаётся валидным до тех пор, пока соответствующий секрет присутствует в массиве.
При создании токена Iron использует первый пароль:
const sealed = await Iron.seal(
{ id: 123, role: 'admin' },
passwords[0],
Iron.defaults
);
При расшифровке происходит последовательная проверка:
const unsealed = await Iron.unseal(
sealed,
passwords,
Iron.defaults
);
Алгоритм:
Ротация строится как управляемый сдвиг массива ключей, а не замена:
Новый секрет всегда добавляется в начало списка:
passwords.unshift('brand-new-secret-key');
Теперь все новые токены будут шифроваться им.
Старые ключи не удаляются сразу, а остаются в массиве до полного истечения срока жизни всех токенов, созданных с их использованием.
const passwords = [
process.env.IRON_KEY_V3,
process.env.IRON_KEY_V2,
process.env.IRON_KEY_V1
];
Ротация становится безопасной только при наличии стратегии удаления старых секретов.
import Iron from '@hapi/iron';
const getPasswords = () => {
return [
process.env.IRON_KEY_CURRENT,
process.env.IRON_KEY_PREVIOUS,
process.env.IRON_KEY_OLD
].filter(Boolean);
};
export const sealData = async (data) => {
const passwords = getPasswords();
return Iron.seal(data, passwords[0], Iron.defaults);
};
export const unsealData = async (token) => {
const passwords = getPasswords();
return Iron.unseal(token, passwords, Iron.defaults);
};
При использовании нескольких инстансов приложения ключи должны синхронизироваться:
Если один сервер использует новый ключ, а другой нет, система всё равно остаётся работоспособной, пока старые ключи не удалены.
Если ключ удалён преждевременно:
Если ключи расположены в неправильном порядке:
Порядок массива влияет на скорость проверки:
Типичная структура:
[
'current',
'previous',
'older',
'legacy'
]
Ротация ключей должна учитывать срок жизни токенов:
Комбинация Iron + TTL позволяет безопасно обновлять ключи без механизма централизованного отзыва токенов.
В устойчивых системах часто применяется перекрывающая модель:
Каждый следующий этап не ломает предыдущий, а накладывается поверх него, формируя непрерывную цепочку совместимости.
При большом количестве проверок токенов важны нюансы:
Iron часто используется через Hapi для защищённых cookie:
Пример конфигурации:
server.state('session', {
isSecure: true,
isHttpOnly: true,
encoding: 'iron',
password: passwords[0]
});
При ротации достаточно обновить массив паролей, используемый сервером.
Корректная схема обновления:
Такой подход исключает необходимость принудительной инвалидaции активных сессий и позволяет проводить ротацию незаметно для пользователей и без потери состояния системы