Перейти до основного вмісту

Перевірка підпису вебхука

Сповіщення про оплату надходить на адресу, яку знає лише ваш магазин і наш сервіс. Але адреса може витекти — з логів, з налаштувань, з історії розробки. Щоб відрізнити справжнє сповіщення від підробки, кожен запит підписується секретом вебхука.

Перевіряйте підпис до того, як видати товар або змінити статус замовлення.

Заголовки підпису

ЗаголовокЗначення
X-TimestampЧас надсилання, unix-час у секундах
X-SignatureПрефікс sha256= і HMAC-SHA256 у шістнадцятковому вигляді

Підписується рядок із часу надсилання, крапки й тіла запиту:

1756901234.{"wallet":{...},"project":{...},"invoice":{...},"payment":{...}}

Ключ підпису — поле «Секрет вебхука» в налаштуваннях проєкту. Його можна перевипустити там само, якщо значення скомпрометовано.

Порядок перевірки

  1. Взяти тіло запиту в сирому вигляді, до розбору JSON.
  2. Склеїти значення X-Timestamp, крапку й тіло.
  3. Обчислити HMAC-SHA256 із секретом вебхука.
  4. Порівняти результат з X-Signature порівнянням за сталий час.
  5. Відхилити запит, якщо X-Timestamp сильно розходиться з поточним часом.

Приклади реалізації

<?php
$secret = 'webhook secret from your project settings';

$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';

// Guards against a replayed request
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(400);
exit;
}

$expected = 'sha256='.hash_hmac('sha256', $timestamp.'.'.$body, $secret);

// hash_equals compares in constant time
if (!hash_equals($expected, $signature)) {
http_response_code(403);
exit;
}

$data = json_decode($body, true);

// Handle the order

http_response_code(200);

На що звернути увагу

Підписується сире тіло. Якщо розібрати JSON і зібрати заново, зміняться порядок ключів і розстановка пробілів — підпис не зійдеться. Обчислюйте HMAC до розбору.

У кожної повторної доставки свій підпис. Час надсилання за повтору новий, отже й підпис інший. Не зберігайте підпис для порівняння з майбутніми запитами.

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

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