Vad en JSON Web Token faktiskt innehåller

Inuti en JWT, med huvud, nyttolast och signatur förklarade, standardanspråken, och varför Base64url-avkodning av en token inte är samma sak som att verifiera den.

En JSON Web Token (JWT) är tre textblock hopfogade med punkter. Varje block är Base64url-kodat, och de två första är helt vanlig JSON. Vem som helst som har token kan läsa vad som finns inuti den. Ingenting i en vanlig JWT är krypterat.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9      <- header
eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJBbGV4In0   <- payload
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFW     <- signature

Hopfogat med punkter är det den token du klistrar in i en begäran. Avkoda de två första delarna så får du vanlig JSON:

{ "alg": "HS256", "typ": "JWT" }
{ "sub": "12345", "name": "Alex" }

En verklig nyttolast bär oftast tidsstämplar och en mottagare också:

{
  "iss": "https://auth.example.com",
  "sub": "12345",
  "aud": "api.example.com",
  "iat": 1756000000,
  "exp": 1756003600,
  "roles": ["editor"]
}

Huvudet

Huvudet beskriver hur token är signerad. Två fält spelar störst roll:

  • alg namnger signeringsalgoritmen, till exempel HS256 (HMAC med SHA-256, med en delad hemlighet) eller RS256 (RSA-signatur med SHA-256, signerad med en privat nyckel och kontrollerad med en publik).
  • kid, nyckel-ID:t, är valfritt och talar om för mottagaren vilken av flera nycklar som användes, så att nycklar kan roteras utan att befintliga tokens slutar fungera.

typ är oftast bara JWT och har ingen säkerhetsmässig betydelse.

Nyttolasten och dess anspråk

Nyttolasten är ett JSON-objekt med anspråk, vilket helt enkelt är specifikationens ord för påståenden om tokens subjekt. Vissa anspråksnamn är registrerade av standarden, och de är alla korta:

AnspråkNamnVad det innehåller
issUtfärdareVem som skapade token, oftast en URL eller ett tjänstenamn
subSubjektVem token handlar om, oftast ett stabilt användar-ID
audMottagareVem token är avsedd för, så att en tjänst kan avvisa tokens avsedda för en annan
expUtgångstidTidpunkten efter vilken token måste avvisas
nbfInte föreTidpunkten före vilken token måste avvisas
iatUtfärdad vidNär token skapades
jtiJWT-IDEn unik identifierare, användbar för att spåra eller blockera enskilda tokens

exp, nbf och iat är alla NumericDate-värden, alltså sekunder sedan 1 januari 1970 UTC. Det är sekunder, inte millisekunder. Om en tidsstämpel avkodas till ett datum år 57 000 läser du millisekunder och behöver dividera med tusen.

Allt annat i nyttolasten är vad utfärdaren nu har lagt dit: roller, behörigheter, en e-postadress, ett tenant-ID. Eftersom ett privat anspråksnamn en dag skulle kunna krocka med ett registrerat, sätter utfärdare ofta en URL-liknande prefixnamnrymd på sina egna.

Signaturen

Signaturen beräknas över den exakta texten i de två första delarna hopfogade med en punkt, med algoritmen från huvudet och en nyckel. Ändra ett enda tecken i huvudet eller nyttolasten och signaturen stämmer inte längre.

Med HS256 signerar och verifierar samma hemlighet, så vem som helst som kan kontrollera en token kan också utfärda en. Med RS256 eller ES256 signerar en privat nyckel och en publik nyckel verifierar, vilket är det som låter en identitetsleverantör dela ut tokens som många separata tjänster kan validera utan att hålla något hemligt.

Base64url är inte kryptering

Base64url är samma idé som Base64, med två skillnader: den använder - och _ i stället för + och / så att resultatet är säkert i URL:er, och den avslutande =-utfyllnaden tas oftast bort. Det är en kodning, ett vändbart sätt att skriva bytes som text. Den ger ingen konfidentialitet över huvud taget.

Lägg därför aldrig något känsligt i en JWT-nyttolast: inga lösenord, inga kortnummer, inga interna anteckningar om användaren. Utgå från att den som håller token, och alla som läser den ur en loggfil eller en webbläsarlagring, kan se varje fält.

Det finns ett separat format, JWE, som faktiskt krypterar nyttolasten, och det har fem delar i stället för tre. Om din token har tre delar är den signerad och läsbar.

Att avkoda är inte att verifiera

Det är den här punkten som betyder något. En avkodare visar dig vad en token säger. Den talar inte om för dig om token är äkta. Verifiering är ett separat steg och kräver nyckeln.

För att verkligen lita på en token måste en server:

  1. Kontrollera signaturen mot rätt nyckel.
  2. Kräva den algoritm den förväntar sig, i stället för att lita på fältet alg i token. Två klassiska angrepp kommer av att man hoppar över detta: att sätta alg till none och ta bort signaturen, och att ta en tjänsts publika RSA-nyckel och använda den som HMAC-hemlighet så att en RS256-verifierare luras att köra HS256.
  3. Kontrollera exp och, om det finns, nbf, med en liten tillåten klockavvikelse.
  4. Kontrollera att iss och aud stämmer med vad den här tjänsten förväntar sig.

Först då betyder anspråken något. Fram till dess är nyttolasten en overifierad sträng som kom in över nätverket.

Praktiska anmärkningar

  • Tokens skickas oftast i ett HTTP-huvud som Authorization: Bearer <token>, så håll nyttolasten liten. Varje anspråk du lägger till skickas vid varje begäran.
  • En signerad token förblir giltig tills den går ut. Det finns inget inbyggt sätt att återkalla en, vilket är varför åtkomsttokens tenderar att ha korta livslängder, ofta minuter, med en separat uppdateringstoken som används för att hämta nya.
  • Om en token ser felformad ut, räkna punkterna först. Två punkter och tre delar är en normal signerad JWT. En avhuggen token som klistrats in från en terminal är en mycket vanlig orsak till "invalid signature".
  • Att avkoda en token för att läsa dess utgångstid, dess subjekt eller dess roller under felsökning är helt ofarligt och kräver ingen hemlighet. Det är precis vad nyttolasten är till för.