В распределённых системах, где несколько сервисов взаимодействуют друг с другом, возникает необходимость безопасной передачи данных и проверки их подлинности. Общие ключи (shared secrets) — это фундаментальный механизм, позволяющий сервисам:
Библиотека Iron в экосистеме JavaScript предоставляет удобный способ работы с такими ключами, реализуя симметричное шифрование и защиту данных.
Iron использует симметричную криптографию: один и тот же секретный ключ применяется как для шифрования, так и для расшифровки. Основные операции:
Пример:
const Iron = require('@hapi/iron');
const password = 'super-secret-key';
const data = { userId: 123 };
async function run() {
const sealed = await Iron.seal(data, password, Iron.defaults);
const unsealed = await Iron.unseal(sealed, password, Iron.defaults);
console.log(unsealed);
}
run();
Взаимодействие нескольких сервисов с использованием общего ключа строится по следующей модели:
Общий ключ должен соответствовать строгим требованиям безопасности:
Пример:
IRON_SECRET=3f9c2e7b8a4d... (длинная случайная строка)
Использование:
const password = process.env.IRON_SECRET;
Iron предоставляет набор настроек, которые можно кастомизировать:
const options = {
encryption: {
saltBits: 256,
algorithm: 'aes-256-cbc',
iterations: 100000,
minPasswordlength: 32
},
integrity: {
saltBits: 256,
algorithm: 'sha256',
iterations: 100000
},
ttl: 0
};
Ключевые параметры:
Для корректной работы необходимо обеспечить:
Использование одного ключа длительное время увеличивает риск компрометации. Практика ротации:
Iron напрямую не поддерживает multiple keys, но можно реализовать вручную:
const keys = ['new-secret', 'old-secret'];
async function unsealWithFallback(sealed) {
for (const key of keys) {
try {
return await Iron.unseal(sealed, key, Iron.defaults);
} catch (err) {}
}
throw new Error('Invalid token');
}
Типичные способы передачи:
Пример cookie:
const sealed = await Iron.seal(session, password, Iron.defaults);
res.setHeader('Set-Cookie', `session=${sealed}; HttpOnly; Secure`);
Iron автоматически добавляет подпись (HMAC), которая позволяет:
Если данные были изменены, unseal выбросит ошибку.
Можно задать срок действия данных:
const options = {
...Iron.defaults,
ttl: 60 * 60 * 1000 // 1 час
};
После истечения TTL расшифровка завершится ошибкой.
Общие ключи особенно полезны в:
Сервис A:
const token = await Iron.seal({ service: 'A' }, password, Iron.defaults);
Сервис B:
const payload = await Iron.unseal(token, password, Iron.defaults);
Использование общего ключа имеет ограничения:
Меры защиты:
Рекомендуется не использовать один ключ для всех задач:
const sessionKey = process.env.SESSION_SECRET;
const apiKey = process.env.API_SECRET;
Результат seal — это строка, содержащая:
Пример (сокращённый):
Fe26.2**...encrypted_data...**...hmac...
Этот формат самодостаточен — дополнительных данных для расшифровки не требуется (кроме ключа).
Основные факторы влияния:
Оптимизация:
| Подход | Особенности |
|---|---|
| Iron | Простота, встроенная защита |
| JWT | Подпись без шифрования (по умолчанию) |
| AES напрямую | Требует ручной реализации |
| OAuth / OAuth2 | Сложнее, но более гибко |
Iron особенно удобен, когда:
Использование короткого ключа
const password = '12345'; // небезопасно
Несогласованные настройки
// разные алгоритмы на сервисах → ошибки
Отсутствие TTL
ttl: 0 // данные живут бесконечно
Iron не предназначен только для подписи, но можно хранить минимальные данные и использовать его как защищённый контейнер.
Iron часто используется в связке с HTTP cookies для хранения сессий без сервера.
Позволяет отказаться от централизованного хранилища токенов.
При росте системы:
sealunsealТакая модель обеспечивает баланс между простотой реализации и достаточным уровнем безопасности для большинства внутренних систем.