Podpisanie i weryfikacja wniosków
Podpis wniosku dowodzi autentyczności nadawcy i integralności treści. W przeciwieństwie do TLS (który chroni kanał), zastosowany podpis sprawia, że każda wiadomość jest weryfikowalna i odporna na proxy, pamięć podręczną i opóźnioną dostawę.
Cele:1. Autentyczność (kto wysłał) i integralność (nie zmienił).
2. Wyjątkowość (ochrona przed powtórkami).
3. Oddzielenie produkcji od transportu (działa na szczycie HTTP, kolejki, haki internetowe).
4. Możliwość audytu (powtarzalna kontrola po miesiącach).
1) Model zagrożenia (minimum)
Wymiana nadwozia/nagłówków na trasie.
Powtórz (powtórz uzasadniony wniosek).
Podpis downgrade/strip.
Kradzież tajemnic integracyjnych.
Zegar synchroniczny (zegar skew) i długie kolejki.
2) Wybór prymitywnego
HMAC (symetria): prosty i szybki, klucz jest przechowywany po obu stronach. Nadaje się do haków B2B i wewnętrznych interfejsów API.
RSA/ECDSA (asymetria): klucz prywatny od nadawcy, klucz publiczny od odbiorcy. Nadaje się do otwartych integracji i kiedy ważne jest, aby nie dzielić się tajemnicą.
mTLS: wzajemne uwierzytelnianie warstwy transportowej często połączone z podpisem NMAC/ciała.
JWT/JWS: wygodne dla żetonów na okaziciela i samowystarczalnych znaczków; aby podpisać ciało, lepiej jest używać kanonicyzacji + JWS Odłączone/HTTP Sygnatury wiadomości.
Podpisy wiadomości HTTP (podpis wybranych części wniosku): nowoczesne podejście do REST.
Zalecenie: dla webhooks - HMAC + timestamp + nonce + body canonicalization; dla publicznego API - sygnatury wiadomości HTTP lub JWS; przy wysokim ryzyku - dodać mTLS.
3) Kanonizacja (co dokładnie podpisujemy)
Musisz podpisać deterministyczny ciąg, który jest równie możliwy do odzyskania przez obie strony.
Skład odniesienia:
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
Rząd całkowity:
canonical = join("\n", fields)
signature = HMAC(secret, canonical) # или ECDSA_sign(private_key, canonical)
Zasady:
- Normalizacja ścieżki i kolejności parametrów zapytania.
- Spacje/unicode/case - fix (na przykład nagłówki dolne, wykończenie).
- Duże ciała - hash (Digest), nie włączać „jak jest”.
4) Format tytułu
Przykład dla 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
Przykład asymetrii (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)"
Gdzie 'kid '/' keyId' pozwala wybrać klucz z rejestru (patrz obrót).
5) Weryfikacja na końcu odbioru
Pseudokoda: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"
Porównanie HMAC w czasie stałym, przechowywanie „nonce ”/„ (ts, event_id)” w szybkim KV (TTL ≥ oknie dostawy).
6) Anty-powtórka i okna
Timestamp + Nonce: odrzucić żądania starsze niż '± Α' (np. 5 min) i nonce ponownie próbuje w tym oknie.
Dla webhooks: użyj stabilnego 'event _ id' i tablicy odbiorczej - jest to bardziej niezawodne niż tylko nonce.
Ponowna dostawa (przekładki) powinna korzystać z tej samej ts/nonce/event_id, a nie generować nowe.
7) Wieloosobowy najemca i regiony
Przechowuj klucze na lokatora/region: 'kid = <najemca>: <region>: <key _ id>'.
Oddzielne tajne puli i limity; obserwować pobyt danych.
W nagłówkach/kanonizacjach należy wskazać 'X-Najemca', a region jest częścią sprawdzanego kontekstu.
8) Zarządzanie kluczem i rotacja
Rejestr kluczy (KMS/Vault): 'kid', typ, algorytm, status ('active', 'deprecating', 'retired'), 'valid _ from/valid _ to'.
Dual-secret: trzymać aktualny i następny klucz jednocześnie (odbiornik akceptuje oba).
Rotacja w harmonogramie i na wydarzeniu (kompromis).
Klucz do szpilek (jeśli to możliwe) i ograniczenie dostępu do kluczowych materiałów.
Rejestry dostępu do kluczy i działań z nimi.
9) Połączenie z mTLS i OAuth
mTLS sprawdza kanał i „kim jesteś” na poziomie certyfikatu.
Podpis chroni komunikat (przydatny poprzez serwery proxy/bufory/kolejki).
OAuth/JWT uzupełnia uwierzytelnianie/autoryzację, ale sam w sobie nie gwarantuje integralności organizmu (chyba że jest podpisany w kanonik).
Najlepsze praktyki: mTLS + podpis nadwozia (Digest) + HMAC/ECDSA + short 'ts' -interval.
10) Błędy i kody odpowiedzi
"401 SIGNATURE_INVALID' jest nieprawidłowym podpisem/algorytmem.
"401 KEY_REVOKED' -" dziecko "jest nieważne/wygasło.
"400 TIMESTAMP_OUT_OF_RANGE' - zegar/okno.
'409 NONCE_REPLAYED' - Wykryto redo.
'400 DIGEST_MISMATCH' - ciało zmienione.
"415 UNSUPPORTED_ALGORITHM' to nierozwiązany" alg ".
"429 TOO_MANY_ATTEMPTS' - przepuszczanie klucza/lokatora.
Kopnij dokładną przyczynę w odczytywalnym dla maszyny 'error _ code'; nie zwracaj tajemnic/kanonik „jak jest”.
11) Obserwowalność i audyt
Metryka:- 'verify _ p95 _ ms', 'verify _ error _ rate', 'digest _ mismatch _ rate', 'replay _ blocked _ rate', 'alg _ usage {hmac, ecdsa}', 'clock _ skew _ ms'.
- Kłody (strukturalne): "dziecko", "alg", "lokator", "region", "ts'," nonce "," digest _ hash "," decyzja "," powód ".
- Śledzenie: podpis atrybutów. dzieciak „,” podpis. alg ',' podpis. ts_skew'.
- Audyt: niezmienny dziennik rotacji, kluczowe flagi użytkowania i tolerancji.
12) Wydajność
Hash ciała przez strumieniowanie (nie przechowywać go w pamięci).
Cache klucze publiczne przez 'dziecko' z krótkim TTL i niepełnosprawność przez wydarzenie.
Na krawędzi/bramce dokonaj wstępnych kontroli (ts/nonce/format).
HMAC szybciej niż ECDSA; ECDSA jest wygodniejsza w przypadku integracji zewnętrznych i klawiszy „niezdecydowanych”.
13) Badanie
Zestawy opraw: te same żądania → ta sama kanonizacja/podpis; brudne miejsca/kolejność zapytań/→ nagłówki są stabilne.
Negatywne: nieprawidłowe 'kid/alg', zmodyfikowane ciało/host, powtarzanie nonce, przestarzałe ts, skew zegara.
Oparte na właściwościach: Wszelkie równorzędne zapytania tworzą jeden kanoniczny ciąg.
Interop: kontrole językowe (Go/Java/Node/Python).
Chaos: opóźnienia, rekolekcje, zmiany klucza podczas lotu.
14) Playbooks (książki startowe)
1. "PODPIS _ INVALID 'spike
Sprawdź obrót klucza, nieprawidłowe uzgodnienie zegara, zmiany kanoniczności w nadawcy.
Tymczasowo włączyć „podwójną akceptację” dla starego „dziecka”, powiadom partnera.
2. „POWTÓRZONY” wzrost
Zwiększ TTL przechowywania nonce, sprawdź przekładnie w nadawcy, sprawdź skew zegara.
Nadmiar nadużycia IP/ASN na krawędzi.
3. „DIGEST _ MISMATCH” masowo
Sprawdź nagłówki proxy/compression/rewriting; naprawić wersję kanonizacyjną.
Wyłączyć intruzy ciała/nagłówka.
4. Kluczowy kompromis
Natychmiast odwołaj 'dziecko', przetłumacz na 'next _ kid', zregeneruj wszystkie sekrety/żetony, dostęp do audytu.
15) Typowe błędy
Podpisanie „części ciała” lub JSON bez ustalania kolejności → podatność na permutację pola.
Brak 'Digest' → proxy może zmienić ciało niezauważone.
Długie 'ts' okno bez nonce jest → otwarte do powtórzenia.
Przechowywanie tajemnic w zmiennych środowiskowych bez KMS/Vault.
Porównaj podpis nie w stałym czasie.
Ignoruj 'host '/' path' w kanonicalizacji → naprzód atak.
Wymieszać 'dzieciak' różnych najemców i regionów.
16) Lista kontrolna przedsprzedaży
- Zdefiniowany format kanonizacyjny (metoda, ścieżka + zapytanie, typ treści, Digest, ts, nonce, host, najemca).
- Wdrożone HMAC/ECDSA z „dzieciakiem”, rejestrem kluczy i dual-secret.
- W zestawie anty-replay (nonce + ts) i inbox/event_id przechowywanie haków webowych.
- Skonfigurowane kody błędów/zasady retray i przepustowości na najemcę/klucz.
- Obserwowalność: weryfikacja mierników, kłód, śladów, wpisów do wybuchów.
- Rotacja klucza jest zautomatyzowana; prawa audytu i dostępu są ograniczone.
- Zestawy do testów kompatybilności kanonizacyjnej i interlanguage.
- Dokumentacja dla integratorów z przykładem w 3-4 językach i poprawkach.
- mTLS włączony do integracji wrażliwych; JWT jest używany tylko jako dodatek, a nie zamiennik do podpisu ciała.
Wnioski
Podpisywanie i weryfikowanie żądań nie jest „jednym nagłówkiem”, ale dyscypliną: wyraźna kanonizacja, krótkie okna czasu, anty-powtórka, rotacja klucza i obserwowalność. Zbuduj jeden standard dla wszystkich integracji (API i webhaki), użyj 'kid '/KMS, zaakceptuj dwa klucze podczas obrotu, a kontury staną się odporne na spoofing, przewidywalne i łatwe do audytu.