Перевірка HMAC-підпису webhook: як зробити правильно

Будь-хто, хто знає — або вгадає — адресу вашого вебхук-ендпоінту, може надіслати POST-запит із JSON-тілом, що виглядає точнісінько як справжня подія: та сама структура, ті самі назви полів, повністю фальшива. Підпис закриває цю прогалину: доводить, що корисне навантаження прийшло від власника спільного секрету і що в ньому нічого не змінили під час передачі. Stripe, GitHub і більшість серйозних провайдерів підписують якимось варіантом тієї самої схеми HMAC, тож механіка тут майже універсальна — конкретний приклад — це власна, реальна, актуальна схема Olmira, включно з назвами заголовків.

Що насправді доводить HMAC

HMAC (Hash-based Message Authentication Code) починається із секрету, який знають обидві сторони і ніхто інший. Відправник хешує корисне навантаження разом із цим секретом і додає результат; ви, володіючи тим самим секретом, обчислюєте заново і порівнюєте. Збіг доводить одразу дві речі: повідомлення справді надійшло від того, хто володіє секретом — жодне знання вмісту не дозволяє зловмиснику підробити хеш, — і його не змінили після підписання, бо навіть одна змінена літера дає зовсім інший хеш.

Точна схема, яку використовує Olmira

Кожна вихідна доставка вебхука несе три заголовки: X-Aether-Signature, X-Aether-Webhook-Id і X-Aether-Event. (Префікс заголовка — Aether, а не Olmira: це спадок внутрішньої кодової назви платформи; на роботу схеми це ніяк не впливає, змінюється лише буквальна назва заголовка.)

Перевірка доставки простими словами

Візьміть сире тіло запиту — точні байти, як їх доставлено, до будь-якого парсингу JSON, — додайте перед ним мітку часу із заголовка підпису і крапку, обчисліть HMAC цього рядка із секретом вашого ендпоінту й порівняйте результат з отриманим підписом, використовуючи порівняння за постійний час. Вбудований модуль Node crypto покриває все це без жодної залежності; саме в попередніх перевірках нижче правильні реалізації насправді відрізняються від зламаних.

Помилки, через які перевірка не проходить

Майже кожне звернення «мій підпис ніколи не збігається» зводиться до однієї з невеликої кількості причин. Хешування заново розібраного або заново серіалізованого тіла замість точних сирих байтів — з великим відривом найчастіша: пробіли, порядок ключів чи формат чисел можуть мовчки змінитися, коли тіло проходить через JSON-парсер і зворотне складання в рядок, а будь-яка зміна взагалі дає інший хеш. Забути, що позначка часу — частина того, що підписується, тобто хешувати саме лише тіло, без префікса ., — друга за поширеністю, і її легко припуститися, бо тіло — більш «очевидне», що хочеться хешувати.

Перш ніж довіряти цьому в продакшені

1

Спершу перевірте вікно часових міток

Відхиляйте все, що виходить за невеликий допуск (Olmira публікує 300 секунд, тобто п'ять хвилин, як власне орієнтовне значення), перш ніж витрачати час процесора на хешування: застарілий підпис не заслуговує на порівняння.

2

Порівнюйте за сталий час

Використовуйте примітив порівняння за сталий час із вашої мови, а не звичайну перевірку на рівність, щоб розбіжність ніколи не видавала за часом, наскільки близькою була спроба.

3

Переконайтеся, що ви хешуєте сире тіло запиту

Хоча б раз під час налаштування запишіть у лог точний рядок, який ваш код збирається хешувати, і порівняйте його побайтово з тим, що насправді надіслала тестова доставка.

4

Урахуйте зміну секретного ключа

Хоч би де ви зберігали секрет, зробіть його заміну однорядковою зміною конфігурації: якщо ротувати його в панелі керування й не оновити тієї ж миті, усі доставки почнуть падати, доки ви не наздоженете.

Як це влаштовано в Olmira

Кожна з 22 webhook-подій Olmira — замовлення, бронювання, платежі, рахунки, звернення до підтримки та інші — підписується точно так, як описано вище, без винятків і без непідписаних типів подій. Кожен endpoint, який ви реєструєте, отримує власний незалежний секрет, тож витік в одній інтеграції ніколи не компрометує іншу. Перед запуском дія «Надіслати тест» у налаштуваннях endpoint надсилає справжню, повністю підписану зразкову доставку тим самим шляхом у коді, що й бойова подія, — з тими самими заголовками й тією самою структурою конверта, — тож ви можете перевірити свій верифікатор на реальній схемі, не чекаючи, поки її спричинить справжнє замовлення чи бронювання. Повна платформа конекторів, частиною якої це є, — імпорт CSV, заплановані вивантаження та вхідні надсилання поряд із вихідними webhooks — це Інтеграції.

Зберіть інтеграцію один раз — і довіряйте їй

Безкоштовний пробний період 30 днів. Зареєструйте ендпоінт і надішліть собі справжню підписану тестову доставку за лічені хвилини.