Skip to content

Безопасность интеграции

Данный раздел описывает основные механизмы защиты, используемые при взаимодействии вашей системы с нашей платформой.
В рамках безопасности применяются два ключевых подхода:

  • авторизация всех API-запросов;
  • проверка подлинности входящих webhook-уведомлений.

Корректная реализация этих механизмов является обязательной.


Авторизация запросов к API

Section titled “Авторизация запросов к API”

Для доступа к API используется API-ключ, который создаётся в личном кабинете мерчанта.
Он служит идентификатором доверенной стороны и подтверждает право на выполнение запросов.

API-ключ должен передаваться в каждом запросе в HTTP-заголовке:

X-Secure-Key: your-api-key-value
POST /example/endpoint HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-Secure-Key: your-api-key-value
{
"field1": "value1",
"field2": "value2"
}

Для защиты от поддельных уведомлений все webhook-запросы подписываются. Подпись передаётся в HTTP-заголовке x-signature.

Проверка подписи позволяет убедиться, что:

  • запрос отправлен нашей системой;
  • содержимое запроса не было изменено.

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

Section titled “Порядок проверки подписи”
  1. Получите тело запроса в исходном виде (raw JSON).
  2. Извлеките значение заголовка x-signature.
  3. Сформируйте подпись на основе тела запроса и API-ключа.
  4. Сравните вычисленную подпись с полученной.

Алгоритм формирования подписи

Section titled “Алгоритм формирования подписи”

Для генерации подписи используется алгоритм HMAC-SHA256.

В расчёте участвуют:

  • тело запроса (без каких-либо изменений);
  • API-ключ, используемый как секрет.

Результат вычисления кодируется в hex-формате.


const crypto = require('crypto');
function verifySignature(apiKey, body, signature) {
const expected = crypto
.createHmac('sha256', apiKey)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex')
);
}

import * as crypto from 'crypto';
export function verifySignature(
apiKey: string,
body: string,
signature: string
): boolean {
const expected = crypto
.createHmac('sha256', apiKey)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex')
);
}

import hmac
import hashlib
def verify_signature(api_key: str, body: str, signature: str) -> bool:
expected = hmac.new(
api_key.encode(),
body.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)

function verifySignature(string $apiKey, string $body, string $signature): bool {
$expected = hash_hmac('sha256', $body, $apiKey);
return hash_equals($expected, $signature);
}

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class WebhookSignatureValidator {
public static boolean verify(
String apiKey,
String body,
String signature
) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(apiKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = mac.doFinal(body.getBytes(StandardCharsets.UTF_8));
return MessageDigest.isEqual(
toHex(hash).getBytes(),
signature.getBytes()
);
}
private static String toHex(byte[] data) {
StringBuilder sb = new StringBuilder();
for (byte b : data) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}

func verifySignature(apiKey, body, signature string) bool {
mac := hmac.New(sha256.New, []byte(apiKey))
mac.Write([]byte(body))
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expected))
}

Если подпись не прошла проверку, webhook-запрос должен быть отклонён с ответом:

HTTP 401 Unauthorized

Запросы с некорректной подписью не должны обрабатываться бизнес-логикой.


  • Подпись всегда проверяется до обработки данных
  • Тело запроса должно использоваться в неизменённом виде
  • Любое расхождение подписи считается критической ошибкой

Данные меры обязательны для обеспечения безопасной и стабильной работы интеграции.