JWT: structura și vulnerabilitățile
1) Ce este JWT și unde este utilizat
JWT este un container autonom compact în formatul "Base64Url (antet). Base64Url (sarcină utilă). Base64Url (semnătură) ".
Utilizat pentru:- JWS (jetoane semnate - autenticitate/integritate),
- JWE (token-uri criptate - confidențialitate),
- OIDC/OAuth2 ca jetoane de acces/ID, precum și autentificarea service-to-service.
Pro: autonomie, cachability, low deasupra capului. Contra: risc de validare incorectă, cazuri complexe de rechemare.
2) Structura JWT
2. 1 Antet (JSON)
Minim: algoritm și identificator cheie.
json
{ "alg": "ES256", "kid": "jwt-2025-10", "typ": "JWT" }
„alg”: semnătură/algoritm de criptare (RS256/ES256/PS256/HS256 etc.).
'kid': pointer la cheie (pentru rotația JWKS).
Surse cheie opționale: „jku”, „x5u” (a se vedea vulnerabilitățile § 6. 3).
2. 2 Sarcină utilă (JSON)
Timbre standardizate:- "iss' (emitent)," aud "(audienţă)," sub "(subiect)
- „exp” (timp de expirare), „nbf” (nu înainte), „iat” (emis)
- 'jti' (token ID, revocabil)
- domenii-timbre: 'domeniu/roluri', 'chiriaș', 'kyc _ level' etc.
2. 3 Semnătură
JWS = 'semn (base64url (antet) + „.” + base64url (sarcină utilă), private_key)'
Verificare: cheie publică strict corespunzătoare și exact algoritmul pe care serverul îl așteaptă.
3) Verificarea invarianților de bază
1. Algoritmul este fixat de configurația serverului de resurse (allow-list) și nu este de încredere cu conținutul the 'header. alg ".
2. Verificați "iss' și" aud "pentru o potrivire exactă," exp/nbf "- ținând cont de micul" clock _ skew "(± 30-60).
3. Refuzați jetoanele fără „copil” numai dacă există o singură cheie și fără rotație; în caz contrar, cere „copil”.
4. Nu aveți încredere în nicio ștampilă fără autorizație la nivel de obiect (BOLA-first).
5. Parsarea - după verificarea cripto; controale de dimensiuni de bază înainte de decodare.
4) JWS vs JWE
JWS: semnat, dar ușor de citit. Nu puneți în sarcină utilă PII/secrete.
JWE: criptează sarcina utilă; integrarea este mai dificilă, modelul cheie este critic.
În majoritatea API-urilor, interdicția JWS + privind datele sensibile în sarcină utilă este suficientă.
5) Ciclu de viață token
Acces: pe termen scurt (5-30 minute).
Reîmprospătare: mai lung (7-30 zile), rotit-la-utilizare (o singură dată), păstrați „lista neagră” „jti/sid”.
Revocare: listează 'jti' cu TTL, introspecție pentru jetoane opace, abreviere 'exp' pentru incidente.
Rotație cheie: JWKS cu suprapunere (vechi + nou), a se vedea articolul „Rotație cheie”.
6) Vulnerabilități frecvente și cum să le închideți
6. 1 'alg = substituţie none '/algoritm
Linia de fund: Serverul are încredere în câmpul 'alg' și acceptă un jeton nesemnat.
Protecție: lista de algoritmi pe server; respinge 'none' şi valorile neaşteptate.
6. 2 RS256→HS256 swap (simetrizare)
Linia de fund: un atacator înlocuiește 'alg' cu HS256 și folosește cheia publică ca secret HMAC.
Protecție: legați cheia de algoritm cu configurație; nu amestecați furnizorii simetrici/asimetrici într-un 'copil'.
6. 3 Injecţie cheie („copil/jku/x5u”)
Scenarii:- 'jku' indică un JWKS controlat de atacator (va aluneca cheia).
- "x5u "/" x5c' abuzează de certificate externe.
- 'kid' cu/SQL cale de injectare ('.. "/../privkey. pem „” sau „” SAU 1 = 1 „--”).
- Ignorați șterse 'jku/x5u' sau filtru de domenii stricte allow-list.
- 'kid' ar trebui să fie utilizat numai ca o cheie în directorul local (tabel/cache), fără căi de fișiere/concatenări SQL.
- Încărcare JWKS de la adrese URL de încredere, TTL scurt, semnătură/canal de fixare.
6. 4 Secretele slabe ale HS256 (forța brută)
Linia de fund: HMAC secret este scurt/scurgeri → semnătură spoofing.
Protecție: utilizați asimetrie (RS/ES/PS) sau lungime secretă ≥ 256 biți, secrete - numai în KMS.
6. 5 Timbre lipsă/nevalide
No 'aud '/' iss '/' exp' → token este cross-service sau infinit.
Prea mult „exp” → riscul de compromis.
Protecție: necesită un set complet de mărci, „exp” scurt, „nbf ”/„ iat” validat cu „clock _ skew”.
6. 6 Replay și furt de jetoane
Esență: interceptarea/repetarea unui token (scurgere în jurnale, XSS, MitM fără TLS).
Protecție:- TLS везде, 'Secure' + 'HttpOnly' cookie, SameSite = Lax/Strict.
- DPoP/PoP (legarea unui token de o cheie client) și/sau mTLS pentru parteneri.
- Scurt „exp”, reîmprospătare-rotație, dispozitiv de legare.
6. 7 XSS/Scurgeri de stocare
Linia de fund: Stocarea JWT în 'localStorage '/' sessionStorage' → este disponibilă pentru JS.
Protecție: stocați jetoanele de acces în HttpOnly-cookie (dacă modelul cookie este posibil) + Tipuri stricte de CSP/încredere.
Pentru SPA fără cookie-uri - izolați tokenul în memorie, trăiți minim, protejați împotriva XSS.
6. 8 CSRF
Concluzie: în timpul sesiunilor de cookie-uri, cereri de la un site terț.
Protecție: SameSite, jetoane anti-CSRF (dublă trimitere), verificare 'Origine/Referer', filtre Fetch-Metadate.
6. 9 Abuz supradimensionat/dimensiune
Gist: sarcină utilă/titluri uriașe, DoS la parsare.
Protecție: limite de mărime titlu/corp, respingere timpurie 431/413, set fix de ștampile.
6. 10 Înlocuirea „typ ”/„ cty”
Esență: confuzie de tipuri („typ:” JWT „”), obiecte imbricate JOSE.
Protecție: ignora „typ/cty” pentru securitate, se bazează pe algoritmi fixe și schema de branding.
7) Token de stocare și transfer
7. 1 Server API-uri (machine-to-machine)
mTLS/HMAC, de preferință asimetrie pentru JWT, canale prin plasă.
Magazin cheie - KMS/HSM, rotație programată, suprapunere JWKS.
7. 2 clienți ai browserului
HttpOnly Secure Cookie для acces/reîmprospătare; scurt TTL; actualizare - prin „reîmprospătare silențioasă” cu 'SameSite = None' only sub HTTPS.
CSP strict, tipuri de încredere, protejați împotriva XSS; pentru SPA - dacă este posibil, nu stocați tokenul pe disc.
8) JWKS, rotație și rechemare
JWKS este publicat de către autorizator; consumatorii memorie cache timp de 5-15 minute.
Planul de rotație: adăugați un nou „copil” → începeți-le semnarea → după N zile elimina cel vechi de la JWKS → purjare.
Feedback: listele „jti/sid” cu TTL; în cazul unui incident, reduceți temporar „exp” și forța de deconectare (dezactivați reîmprospătarea).
9) Minimizarea multi-chiriașilor și a datelor
Includeți „chiriaș ”/„ org” în token numai dacă este necesar prin arhitectură; în caz contrar, trageți atributele din PDP prin 'sub'.
Fără IIP-uri; set minim de timbre → risc mai mic de scurgeri și corelare.
10) Lista de verificare a validării practice (server de resurse)
- Parsim numai după verificarea semnăturii și a limitelor de dimensiune de bază.
- 'alg' de la configurare; respinge cele neaşteptate.
- Verificați "iss' ∧" aud "∧" exp "∧" nbf "∧" iat "(cu" clock _ skew ").
- Verificați 'kid' pe directorul local/JWKS (scurt TTL).
- Filtrați/normalizați indicatorii externi ('jku/x5u' - numai lista permisă).
- Lungimea/compoziția ștampilei limită (schema).
- Apply Object Resource Authorization (BOLA-first).
- Log 'kid', 'sub', 'aud', 'iss', 'jti', 'exp', 'chiriaș', 'trace _ id' (fără PII).
- Metrica erorilor de semnătură, întârzieri, audituri de rotație.
11) Exemple de politici sigure (pseudo)
11. 1 Configurarea așteptărilor algoritmilor
yaml jwt:
expected_issuer: "https://auth. example. com"
expected_audience: ["wallet-service"]
allowed_algs: ["ES256"] # fix the jwks_url: "https ://auth. example. com/.well-known/jwks. json"
jwks_cache_ttl: 600s clock_skew: 60s required_claims: ["iss","aud","sub","exp","iat"]
11. 2 Dropping de la distanță „jku/x5u”
yaml reject_untrusted_key_sources: true allowed_jku_hosts: ["auth. example. com"] # if absolutely necessary
11. 3 Lista de feedback de probă (Redis)
pseudo if redis. exists("revoke:jti:" + jti) then deny()
if now() > exp then deny()
12) Observabilitate și incidență
Метрики: 'jwt _ verify _ fail _ total {reason}', 'jwt _ expired _ total', 'jwks _ refresh _ total', доля 'kid'.
Jurnale (structurate): 'iss/aud/sub/kid/jti/exp/chiriaș/trace _ id', motiv pentru eșec.
Tablouri de bord: „expirarea în curând”, o creștere a erorilor de validare, distribuirea pe regiuni/clienți.
Alerte: creșterea „verify _ fail” (semnătură/algoritm), erori JWKS, cota de jetoane expirate.
13) Antipattern
Trust 'alg' de la token; suport 'none'.
Jetoane de acces cu durată lungă de viață și fără rotație de reîmprospătare.
HS256 cu un secret scurt/secret în ENV fără KMS.
Accept 'jku/x5u' din orice domeniu; încărcați dinamic JWKS fără lista de permise.
Pune PII/secrete în sarcină utilă JWS.
Stocați jetoane în 'LocalStorage' atunci când există riscuri XSS.
Suprima erorile de validare (retur 200 s „eroare moale”).
Fără verificări BOLA și bazându-se doar pe „domeniul de aplicare/rol”.
14) Specificul iGaming/Finanțe
Mărci: 'kyc _ level', 'risk _ tier', 'chiriaş', strict 'aud'.
Scurt TTL pentru operațiuni de scriere (depozite/ieșiri), PoP/DPoP sau mTLS pentru rute critice.
Audit de reglementare: jurnale neschimbabile de intrări/defecțiuni, stocarea jurnalelor în limitele regiunii.
Partenerii/PSP au chei separate/„ aud ”, chei de chiriaș și JWKS separate.
15) Lista de verificare Prod Readiness
- Hard permite-lista de algoritmi; „None” nu este permis.
- „iss/aud/exp/nbf/iat/jti” sunt verificate; scurt „exp”.
- suprapus JWKS, scurt TTL cache; monitorizarea acţiunilor „puştiului”.
- Reîmprospătare - rotire la utilizare; listele „jti/sid” cu TTL; review playbook.
- PoP/DPoP sau mTLS pe rutele critice.
- HttpOnly-cookie-uri pentru browser, CSP/Tipuri de încredere vs. XSS; Protecția CSRF.
- Fără PII în sarcină utilă; set minim de mărci.
- Validare și eșec metrici/busteni; alerte JWKS/verify_fail.
- Teste de scenariu negative: RS→HS swap, 'kid' -injections, 'jku' spoofing, oversize, clock-skew.
16) TL; DR
Fixați algoritmul și tastele de pe partea serverului, nu aveți încredere în „alg” din token, cereți „iss/aud/exp/nbf/iat/jti”. Rotiți tastele prin suprapunerea JWKS, păstrați jetoane de scurtă durată și reîmprospătați de unică folosință. Stocați jetoanele în siguranță (HttpOnly-cookie pentru web), minimizați ștampilele, nu puneți PII. Închideți vectorii „jku/x5u/kid”, evitați HS256 cu secrete slabe, adăugați PoP/DPoP sau mTLS pe căi critice și faceți întotdeauna verificări BOLA la nivelul resurselor.