Firma e verifica delle richieste
La firma della query dimostra l'autenticità del mittente e l'integrità del contenuto. A differenza di TLS (che protegge il canale), la firma applicativa rende ogni messaggio verificabile e resistente al proxy, alla cache e alla spedizione posticipata.
Obiettivi:1. Autenticità (chi ha inviato) e integrità (non modificata).
2. Esclusività (protezione da repliche).
3. Distacco dal trasporto (funziona su HTTP, code, webhoop).
4. Verifica (riproducibile mesi dopo).
1) Modello di minaccia (minimo)
Cambio corpo/intestazione nel percorso di percorrenza.
Repliche (ripetizione di una richiesta legittima).
Downgrade/strip intestazioni firma.
Rubare i segreti dell'integrazione.
Orologio non incrono (clock skew) e lunghe code.
2) Selezione di un primitivo
HMAC - Semplice e veloce, la chiave è memorizzata su entrambi i lati. Adatto per hub B2B e API interne.
RSA/ECDSA (asimmetria) - La chiave è privata al mittente, pubblica al destinatario. Adatto per le integrazioni aperte e quando è importante non condividere un segreto.
mTLS - autenticazione reciproca a livello di trasporto; spesso combinato con NMAS/firma del corpo.
JWT/JWS: utile per i token bearer e i marchi autosufficienti; per firmare il corpo è meglio utilizzare la canonizzazione + JWS Detached/HTTP Messaggistica Signures.
HTTP Messaggistica (firma delle parti selezionate della query) - Approccio moderno per REST.
Raccomandazione per webhook - HMAC + timestamp + nonce + canonizzazione del corpo; per API pubblica - HTTP Messaggistica Signature o JWS; A rischi elevati, aggiungete un mTLS.
3) Canonicalizzazione (cosa firmiamo esattamente)
È necessario firmare una stringa determinata, ripristinata ugualmente da entrambe le parti.
Composizione arbitrale:
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
Riga finale:
canonical = join("\n", fields)
signature = HMAC(secret, canonical) # или ECDSA_sign(private_key, canonical)
Regole:
- Regolate il percorso e l'ordine dei parametri query.
- Spazi/unicode/maiuscole - Fissa (ad esempio, titoli lower-case, trim).
- Grandi corpi - Hashtag (Digest), non accendere «com'è».
4) Formato intestazione
Esempio per 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
Esempio di asimmetria (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)"
Dove «kid »/« keyId» consente di selezionare una chiave dal Registro di sistema (vedi rotazione).
5) Verifica sul lato ricevente
Pseudocode: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 confronto HMAC, memorizzazione dì nonce '/' (ts, event _ id) 'nella finestra rapida KV (TTL).
6) Anti-repliche e finestre
Timestamp + Nonce: respinge le richieste più vecchie dì Ehi "(ad esempio, 5 minuti) e le ripetizioni nonce in questa finestra.
Per i webhoop, usare «event _ id» stabile e una tabella inbox è più affidabile di solo nonce.
La ripartizione (retrai) deve utilizzare gli stessi ts/nonce/event _ id, non generarne di nuovi.
7) Multi-tenente e regioni
Memorizza le chiavi per tenant/region: 'kid = <tenant>: <region>: <key _ id>'.
Separare pool di segreti e limiti; attenersi alla data residency.
Le intestazioni/canonizzazioni indicano «X-Tenant» e la regione è parte del contesto da verificare.
8) Gestione delle chiavi e rotazione
Registro chiavi (KMS/Vault): «kid», tipo, algoritmo, stato («active», «deprecating», «retired»), «valid _ from/valid _ to».
Dual-secret - Mantenere contemporaneamente la chiave corrente e la chiave successiva (il ricevitore accetta entrambi).
Rotazione pianificata e per evento (compromissione).
Key pinning (se possibile) e limitazione dell'accesso al materiale delle chiavi.
I fogli di accesso alle chiavi e le azioni con esse.
9) Combinazione con mTLS e OAuth
mTLS controlla il canale e «chi sei» a livello di certificato.
La firma protegge il messaggio (utile tramite proxy/caselle/code).
OAUTH/JWT completa l'autenticazione/autorizzazione, ma non garantisce di per sé l'integrità del corpo (a meno che non venga firmato in canonicalizzazione).
Le migliori pratiche sono mTLS + firma corpo (Digest) + HMAC/ECDSA + breve «ts» - intervallo.
10) Errori e codici di risposta
«401 SIGNATURE _ INVALID» è una firma/algoritmo non valida.
«401 KEY _ REVOKED» - «kid» non valido/scaduto.
'400 TIMESTAMP _ OUT _ OF _ RANGE' - orologio/finestra.
«409 NONCE _ REPLAYED» - È stata rilevata una ripetizione.
«400 DIGEST _ MISMATCH» - Il corpo è stato modificato.
«415 UNSUPPORTED _ ALGORITHM» - non risolto «alg».
'429 TOO _ MANY _ ATTEMPTS' - trottling su chiave/tenante.
Prendete a calci la causa esatta in «error _ code»; non restituire segreti/canonizzazioni «com'è».
11) Osservazione e verifica
Metriche:- `verify_p95_ms`, `verify_error_rate`, `digest_mismatch_rate`, `replay_blocked_rate`, `alg_usage{hmac,ecdsa}`, `clock_skew_ms`.
- I loghi (strutturali) sono: «kid», «alg», «tenant», «region», «ts», «nonce», «digest _ hash», «decise», «reason».
- Tracing: attributi dì firma. kid`, `signature. alg`, `signature. ts_skew`.
- Controllo: registro di rotazioni, chiavi e flag di tolleranza invariato.
12) Prestazioni
Accetta il corpo con lo stryming (non tenerlo in memoria).
Memorizza le chiavi pubbliche dì kid "con TTL breve e disabilità per evento.
Su edge/gateway, estrarre i controlli preliminari (ts/nonce/formato).
HMAC più veloce di ECDSA ECDSA è più conveniente per le integrazioni esterne e le chiavi «non condivise».
13) Test
Insiemi di ficstur: identiche richieste, stessa canonizzazione/firma; gli spazi sporchi/l'ordine di query/intestazione sono resistenti.
Negative: errato «kid/alg», corpo modificato/host, ripetizione nonce, vecchio ts, clock skew.
Property-based - Tutte le richieste equivalenti forniscono una riga canonical.
Interop: controlli di lingua crociata (Go/Java/Node/Python).
Chaos: ritardi, retrai, cambio della chiave al volo.
14) Playbooks (runbooks)
1. Sfoglia «SIGNATURE _ INVALID»
Controlla la rotazione delle chiavi, la rassincrona clock, le modifiche alla canonizzazione del mittente.
Attivare temporaneamente dual-accept per il vecchio kid, avvisare il partner.
2. Crescita REPLAYED
Aumenta la TTL di storage nonce, incrocia i retrainer dal mittente, controlla clock skew.
Blocca IP/ASN abusivo su edge.
3. 'DIGEST _ MISMATCH'in massa
Controlla proxy/compressione/sovrascrivere i titoli Fissare la versione della canonizzazione.
Disattiva gli intermediari che violano il corpo/intestazione.
4. Compromettere la chiave
Subito revoke «kid», tradurre in «next _ kid», rigenerare tutti i segreti/token, controllare l'accesso.
15) Errori tipici
Firmare «parte del corpo» o JSON senza fissare l'ordine è vulnerabile al riposizionamento dei campi.
L'assenza dì Digest "del proxy può cambiare il corpo in modo invisibile.
La lunga finestra «ts» senza nonce è stata aperta.
Mantieni i segreti nelle variabili di ambiente senza KMS/Vault.
Paragonare una firma non constant-time.
Ignora «host »/« path» nella canonizzazione dell'attacco di reindirizzamento.
Mescolare «kid» tra tenenti e regioni.
16) Foglio di assegno prima della vendita
- Formato di canonizzazione definito (method, path + query, content-type, Digest, ts, nonce, host, tenant).
- Implementato HMAC/ECDSA con'kid ', registro delle chiavi e dual-secret.
- Incluse le repliche anti-repliche (nonce + ts) e l'archiviazione inbox/event _ id per i webhoop.
- Sono configurati i codici di errore/regola retrae e trottling per tenant/key.
- Osservabilità: metriche verify, fogli, traccia, alert sui picchi.
- Rotazione delle chiavi automatizzata; controllo e diritti di accesso limitati.
- Kit di test per la canonizzazione e compatibilità tra lingue.
- Documentazione per gli integratori con esempio in 3-4 lingue e ficsture.
- Abilitato per le integrazioni sensibili JWT è utilizzato solo come aggiunta, non sostituisce la firma del corpo.
Conclusione
La firma e la verifica delle richieste non è un solo titolo, ma una disciplina: canonizzazione chiara, brevi finestre di tempo, anti-repliche, rotazione delle chiavi e osservabilità. Costruisci un unico standard per tutte le integrazioni (API e webhoop), usa kid/KMS, accetti due chiavi durante la rotazione e i tuoi tracciati diventano resistenti ai sottomenu, prevedibili e facili da controllare.