GH GambleHub

Подпись и верификация запросов

Подпись запроса доказывает подлинность отправителя и целостность содержимого. В отличие от TLS (который защищает канал), прикладная подпись делает каждое сообщение проверяемым и устойчивым к прокси, кэшу и отложенной доставке.

Цели:

1. Аутентичность (кто отправил) и целостность (не изменялось).

2. Неповторяемость (защита от реплеев).

3. Отвязка от транспорта (работает поверх HTTP, очередей, вебхуков).

4. Аудитируемость (воспроизводимая проверка спустя месяцы).

1) Модель угроз (минимум)

Подмена тела/заголовков в пути следования.
Реплей (повтор легитимного запроса).
Downgrade/strip заголовков подписи.
Кража секретов интеграции.
Несинхронные часы (clock skew) и длинные очереди.

2) Выбор примитива

HMAC (симметрия): простой и быстрый, ключ хранится у обеих сторон. Подходит для B2B-вебхуков и внутренних API.
RSA/ECDSA (асимметрия): ключ приватный у отправителя, публичный у получателя. Подходит для открытых интеграций и когда важно не делиться секретом.
mTLS: взаимная аутентификация на транспортном уровне; часто комбинируется с HMAC/подписью тела.
JWT/JWS: удобно для bearer-токенов и самодостаточных клеймов; для подписи тела лучше использовать каноникализацию + JWS Detached/HTTP Message Signatures.
HTTP Message Signatures (подпись выбранных частей запроса): современный подход для REST.

Рекомендация: для вебхуков — HMAC + timestamp + nonce + каноникализация тела; для публичного API — HTTP Message Signatures или JWS; при высоких рисках — добавьте mTLS.

3) Каноникализация (что именно подписываем)

Подписывать нужно детерминированную строку, одинаково восстанавливаемую обеими сторонами.

Референсный состав:

method \n path_with_query_normalized \n content-type \n digest: SHA-256=BASE64(SHA256(body)) \n x-ts: <unix    iso> \n x-nonce: <uuid> \n host \n x-tenant: <tenant_id> \n
Итоговая строка:

canonical = join("\n", fields)
signature = HMAC(secret, canonical)  # или ECDSA_sign(private_key, canonical)
Правила:
  • Нормализуйте путь и порядок query-параметров.
  • Пробелы/юникод/регистр — фиксируйте (например, lower-case заголовков, trim).
  • Большие тела — хешируйте (Digest), а не включайте «как есть».

4) Формат заголовков

Пример для HMAC:

X-Signature-Alg: hmac-sha256
X-Signature: v1=hex(hmac),ts=1730379005,nonce=550e8400-e29b-41d4-a716-446655440000,kid=prov_42
Digest: SHA-256=BASE64(SHA256(body))
X-Tenant: brand_eu
Пример для асимметрии (ECDSA P-256):

Signature: keyId="prov_42", alg="ecdsa-p256-sha256",
ts="2025-10-31T12:30:05Z", nonce="550e...", headers="(request-target) host digest x-tenant",
sig="BASE64(raw_signature)"

Где `kid`/`keyId` позволяет выбрать ключ из реестра (см. ротацию).

5) Верификация на приемной стороне

Псевдокод:
python def verify(request):
1) Basic assert abs (now () - request. ts) <= ALLOWED_SKEW  # напр., 300 с assert not replayed(request. nonce, window = TTL) # store nonce/ts in KV

2) Restore canonical canonical = build_canonical (
method=request. method,
path=normalize_path(request. path, request. query),
content_type=request. headers["content-type"],
digest=hash_body(request. body),
ts=request. ts,
nonce=request. nonce,
host=request. headers["host"],
tenant=request. headers. get("x-tenant")
)

3) Get the key key = key_registry. get(request. kid) # secret (HMAC) или public key (ECDSA)

4) Verify if request signature. alg. startswith("hmac"):
ok = hmac_compare(key. secret, canonical, request. signature)
else:
ok = asym_verify(key. public, canonical, request. signature)

5) Solution if not ok: return 401, "SIGNATURE_INVALID"
return 200, "OK"

Constant-time сравнение HMAC, хранение `nonce`/`(ts, event_id)` в быстрых KV (TTL ≥ окно доставки).

6) Анти-реплей и окна

Timestamp + Nonce: отклоняйте запросы старше `±Δ` (напр., 5 мин) и повторы nonce в этом окне.
Для вебхуков: используйте стабильный `event_id` и inbox-таблицу — это надежнее, чем только nonce.
Повторная доставка (ретраи) должна использовать те же ts/nonce/event_id, а не генерировать новые.

7) Мульти-тенант и регионы

Храните ключи per tenant/region: `kid = <tenant>:<region>:<key_id>`.
Разделяйте пулы секретов и лимиты; соблюдайте data residency.
В заголовках/каноникализации указывайте `X-Tenant` и регион — это часть проверяемого контекста.

8) Управление ключами и ротация

Реестр ключей (KMS/Vault): `kid`, тип, алгоритм, статус (`active`, `deprecating`, `retired`), `valid_from/valid_to`.
Dual-secret: держите одновременно текущий и следующий ключ (приемник принимает оба).
Ротация по расписанию и по событию (компрометация).
Key pinning (по возможности) и ограничение доступа к материалам ключей.
Логи доступа к ключам и действиям с ними.

9) Сочетание с mTLS и OAuth

mTLS проверяет канал и «кто вы» на уровне сертификата.
Подпись защищает сообщение (полезна через прокси/кеши/очереди).
OAuth/JWT дополняет аутентификацию/авторизацию, но сам по себе не гарантирует целостность тела (если его не подписывать в каноникализации).
Лучшие практики: mTLS + подпись тела (Digest) + HMAC/ECDSA + короткий `ts`-интервал.

10) Ошибки и коды ответов

`401 SIGNATURE_INVALID` — неверная подпись/алгоритм.
`401 KEY_REVOKED` — `kid` недействителен/просрочен.
`400 TIMESTAMP_OUT_OF_RANGE` — часы/окно.
`409 NONCE_REPLAYED` — обнаружен повтор.
`400 DIGEST_MISMATCH` — тело изменено.
`415 UNSUPPORTED_ALGORITHM` — неразрешенный `alg`.
`429 TOO_MANY_ATTEMPTS` — троттлинг по ключу/тенанту.

Пинайте точную причину в машинно-читаемом `error_code`; не возвращайте секреты/каноникализацию «как есть».

11) Наблюдаемость и аудит

Метрики:
  • `verify_p95_ms`, `verify_error_rate`, `digest_mismatch_rate`, `replay_blocked_rate`, `alg_usage{hmac,ecdsa}`, `clock_skew_ms`.
  • Логи (структурные): `kid`, `alg`, `tenant`, `region`, `ts`, `nonce`, `digest_hash`, `decision`, `reason`.
  • Трейсинг: атрибуты `signature.kid`, `signature.alg`, `signature.ts_skew`.
  • Аудит: неизменяемый журнал ротаций, использования ключей и флагов допуска.

12) Производительность

Хэшируйте тело стримингом (не держите в памяти).
Кэшируйте публичные ключи по `kid` с коротким TTL и инвалидацией по событию.
На edge/gateway выносите предварительные проверки (ts/nonce/формат).
HMAC быстрее ECDSA; ECDSA удобнее для внешних интеграций и «неразделяемых» ключей.

13) Тестирование

Наборы фикстур: одинаковые запросы → одинаковая каноникализация/подпись; «грязные» пробелы/порядок query/заголовков → устойчивы.
Negative: неверный `kid/alg`, модифицированное тело/host, повтор nonce, устаревший ts, clock skew.
Property-based: любые эквивалентные запросы дают одну canonical-строку.
Interop: кросс-языковые проверки (Go/Java/Node/Python).
Chaos: задержки, ретраи, смена ключа «на лету».

14) Плейбуки (runbooks)

1. Всплеск `SIGNATURE_INVALID`

Проверить ротацию ключей, рассинхрон clock, изменения каноникализации у отправителя.
Временно включить `dual-accept` для старого `kid`, уведомить партнера.

2. Рост `REPLAYED`

Увеличить TTL хранения nonce, сверить ретрайнеры у отправителя, проверить clock skew.
Перекрыть злоупотребляющий IP/ASN на edge.

3. `DIGEST_MISMATCH` массово

Проверить прокси/компрессию/перезапись заголовков; зафиксировать версию каноникализации.
Отключить посредников, нарушающих тело/заголовки.

4. Компрометация ключа

Немедленно revoke `kid`, перевести на `next_kid`, регенерировать все секреты/токены, аудит доступа.

15) Типичные ошибки

Подписывать «часть тела» или JSON без фиксации порядка → уязвимость к перестановке полей.
Отсутствие `Digest` → прокси может изменить тело незаметно.
Длинное окно `ts` без nonce → открыт реплей.
Хранить секреты в переменных окружения без KMS/Vault.
Сравнивать подпись не constant-time.
Игнорировать `host`/`path` в каноникализации → атаки на переадресацию.
Смешивать `kid` разных тенантов и регионов.

16) Чек-лист перед продом

  • Определен формат каноникализации (method, path+query, content-type, Digest, ts, nonce, host, tenant).
  • Реализованы HMAC/ECDSA с `kid`, реестр ключей и dual-secret.
  • Включены анти-реплей (nonce+ts) и хранение inbox/event_id для вебхуков.
  • Настроены коды ошибок/политика ретраев и троттлинг per tenant/key.
  • Наблюдаемость: метрики verify, логи, трассировка, алерты на всплески.
  • Ротация ключей автоматизирована; аудит и права доступа ограничены.
  • Тест-наборы на каноникализацию и межъязыковую совместимость.
  • Документация для интеграторов с примером на 3–4 языках и фикстурами.
  • mTLS включен для чувствительных интеграций; JWT используется только как дополнение, не замена подписи тела.

Заключение

Подпись и верификация запросов — это не «один заголовок», а дисциплина: четкая каноникализация, короткие окна времени, анти-реплей, ротация ключей и наблюдаемость. Постройте единый стандарт для всех интеграций (API и вебхуки), используйте `kid`/KMS, принимайте два ключа при ротации, и ваши контуры станут устойчивыми к подменам, предсказуемыми и удобными для аудита.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Telegram
@Gamble_GC
Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.