En omfattande guide till bästa praxis för säkerhet med JWT (JSON Web Token), som täcker validering, lagring, signeringsalgoritmer och strategier för att motverka vanliga sårbarheter i internationella applikationer.
JWT-tokens: Bästa praxis för säkerhet i globala applikationer
JSON Web Tokens (JWT) har blivit en standardmetod för att säkert representera anspråk mellan två parter. Deras kompakta struktur, användarvänlighet och breda stöd över olika plattformar har gjort dem till ett populärt val för autentisering och auktorisering i moderna webbapplikationer, API:er och mikrotjänster. Deras utbredda användning har dock också lett till ökad granskning och upptäckten av ett flertal säkerhetssårbarheter. Denna omfattande guide utforskar bästa praxis för JWT-säkerhet för att säkerställa att dina globala applikationer förblir säkra och motståndskraftiga mot potentiella attacker.
Vad är JWT:er och hur fungerar de?
En JWT är en JSON-baserad säkerhetstoken som består av tre delar:
- Sidhuvud (Header): Anger typen av token (JWT) och den signeringsalgoritm som används (t.ex. HMAC SHA256 eller RSA).
- Nyttolast (Payload): Innehåller anspråk (claims), som är påståenden om en enhet (vanligtvis användaren) och ytterligare metadata. Anspråk kan vara registrerade (t.ex. utfärdare, subjekt, utgångstid), publika (definierade av applikationen) eller privata (anpassade anspråk).
- Signatur (Signature): Skapas genom att kombinera det kodade sidhuvudet, den kodade nyttolasten, en hemlig nyckel (för HMAC-algoritmer) eller en privat nyckel (för RSA/ECDSA-algoritmer), den angivna algoritmen och signera resultatet.
Dessa tre delar är Base64 URL-kodade och sammanfogade med punkter (.
) för att bilda den slutliga JWT-strängen. När en användare autentiserar sig genererar servern en JWT, som klienten sedan lagrar (vanligtvis i local storage eller en cookie) och inkluderar i efterföljande förfrågningar. Servern validerar sedan JWT:n för att auktorisera förfrågan.
Förstå vanliga sårbarheter med JWT
Innan vi går in på bästa praxis är det avgörande att förstå de vanliga sårbarheterna som är förknippade med JWT:er:
- Algoritmförväxling: Angripare utnyttjar möjligheten att ändra parametern
alg
i sidhuvudet från en stark asymmetrisk algoritm (som RSA) till en svag symmetrisk algoritm (som HMAC). Om servern använder den publika nyckeln som den hemliga nyckeln i HMAC-algoritmen kan angripare förfalska JWT:er. - Exponering av hemlig nyckel: Om den hemliga nyckel som används för att signera JWT:er komprometteras kan angripare generera giltiga JWT:er och utge sig för att vara vilken användare som helst. Detta kan hända på grund av kodläckor, osäker lagring eller sårbarheter i andra delar av applikationen.
- Tokenstöld (XSS/CSRF): Om JWT:er lagras osäkert kan angripare stjäla dem genom Cross-Site Scripting (XSS) eller Cross-Site Request Forgery (CSRF)-attacker.
- Replay-attacker: Angripare kan återanvända giltiga JWT:er för att få obehörig åtkomst, särskilt om tokens har lång livslängd och inga specifika motåtgärder har implementerats.
- Padding Oracle-attacker: När JWT:er krypteras med vissa algoritmer och utfyllnad (padding) hanteras felaktigt, kan angripare potentiellt dekryptera JWT:n och komma åt dess innehåll.
- Problem med klockavvikelse (Clock Skew): I distribuerade system kan klockavvikelser mellan olika servrar leda till fel vid JWT-validering, särskilt med anspråk om utgångstid.
Bästa praxis för JWT-säkerhet
Här är omfattande bästa praxis för säkerhet för att minska riskerna förknippade med JWT:er:
1. Att välja rätt signeringsalgoritm
Valet av signeringsalgoritm är kritiskt. Här är vad du bör tänka på:
- Undvik
alg: none
: Tillåt aldrig attalg
-sidhuvudet sätts tillnone
. Detta inaktiverar signaturverifiering, vilket gör att vem som helst kan skapa giltiga JWT:er. Många bibliotek har patchats för att förhindra detta, men se till att dina bibliotek är uppdaterade. - Föredra asymmetriska algoritmer (RSA/ECDSA): Använd RSA (RS256, RS384, RS512) eller ECDSA (ES256, ES384, ES512)-algoritmer när det är möjligt. Asymmetriska algoritmer använder en privat nyckel för signering och en publik nyckel för verifiering. Detta förhindrar angripare från att förfalska tokens även om de får tillgång till den publika nyckeln.
- Hantera privata nycklar säkert: Lagra privata nycklar säkert med hjälp av hårdvarusäkerhetsmoduler (HSM) eller säkra nyckelhanteringssystem. Checka aldrig in privata nycklar i källkodsregister.
- Rotera nycklar regelbundet: Implementera en strategi för nyckelrotation för att regelbundet byta ut signeringsnycklarna. Detta minimerar effekten om en nyckel någonsin komprometteras. Överväg att använda JSON Web Key Sets (JWKS) för att publicera dina publika nycklar.
Exempel: Använda JWKS för nyckelrotation
En JWKS-slutpunkt tillhandahåller en uppsättning publika nycklar som kan användas för att verifiera JWT:er. Servern kan rotera nycklar, och klienter kan automatiskt uppdatera sin nyckelsamling genom att hämta JWKS-slutpunkten.
/.well-known/jwks.json
:
{
"keys": [
{
"kty": "RSA",
"kid": "key1",
"alg": "RS256",
"n": "...",
"e": "AQAB"
},
{
"kty": "RSA",
"kid": "key2",
"alg": "RS256",
"n": "...",
"e": "AQAB"
}
]
}
2. Validera JWT:er korrekt
Korrekt validering är avgörande för att förhindra attacker:
- Verifiera signaturen: Verifiera alltid JWT-signaturen med rätt nyckel och algoritm. Se till att ditt JWT-bibliotek är korrekt konfigurerat och uppdaterat.
- Validera anspråk: Validera väsentliga anspråk som
exp
(utgångstid),nbf
(not before),iss
(utfärdare) ochaud
(målgrupp). - Kontrollera
exp
-anspråket: Se till att JWT:n inte har löpt ut. Implementera en rimlig livslängd för token för att minimera möjlighetsfönstret för angripare. - Kontrollera
nbf
-anspråket: Se till att JWT:n inte används före sin giltiga starttid. Detta förhindrar replay-attacker innan token är avsedd att användas. - Kontrollera
iss
-anspråket: Verifiera att JWT:n har utfärdats av en betrodd utfärdare. Detta förhindrar angripare från att använda JWT:er utfärdade av obehöriga parter. - Kontrollera
aud
-anspråket: Verifiera att JWT:n är avsedd för din applikation. Detta förhindrar att JWT:er utfärdade för andra applikationer används mot din. - Implementera en spärrlista (valfritt): För kritiska applikationer, överväg att implementera en spärrlista (även känd som en återkallelselista) för att ogiltigförklara komprometterade JWT:er före deras utgångstid. Detta ökar komplexiteten men kan avsevärt förbättra säkerheten.
Exempel: Validera anspråk i kod (Node.js med jsonwebtoken
)
const jwt = require('jsonwebtoken');
try {
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://example.com',
audience: 'https://myapp.com'
});
console.log(decoded);
} catch (error) {
console.error('JWT validation failed:', error);
}
3. Säker lagring av JWT:er på klientsidan
Hur JWT:er lagras på klientsidan påverkar säkerheten avsevärt:
- Undvik Local Storage: Att lagra JWT:er i local storage gör dem sårbara för XSS-attacker. Om en angripare kan injicera JavaScript i din applikation kan de enkelt stjäla JWT:n från local storage.
- Använd HTTP-Only-cookies: Lagra JWT:er i HTTP-only-cookies med attributen
Secure
ochSameSite
. HTTP-only-cookies kan inte nås av JavaScript, vilket minskar XSS-risker. AttributetSecure
säkerställer att cookien endast överförs via HTTPS. AttributetSameSite
hjälper till att förhindra CSRF-attacker. - Överväg refresh-tokens: Implementera en mekanism med refresh-tokens. Kortlivade åtkomsttokens används för omedelbar auktorisering, medan långlivade refresh-tokens används för att få nya åtkomsttokens. Lagra refresh-tokens säkert (t.ex. i en databas med kryptering).
- Implementera CSRF-skydd: När du använder cookies, implementera CSRF-skyddsmekanismer, såsom "synchronizer tokens" eller "Double Submit Cookie"-mönstret.
Exempel: Sätta HTTP-Only-cookies (Node.js med Express)
app.get('/login', (req, res) => {
// ... autentiseringslogik ...
const token = jwt.sign({ userId: user.id }, privateKey, { expiresIn: '15m' });
const refreshToken = jwt.sign({ userId: user.id }, refreshPrivateKey, { expiresIn: '7d' });
res.cookie('accessToken', token, {
httpOnly: true,
secure: true, // Sätt till true i produktion
sameSite: 'strict', // eller 'lax' beroende på dina behov
maxAge: 15 * 60 * 1000 // 15 minuter
});
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true, // Sätt till true i produktion
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 dagar
});
res.send({ message: 'Login successful' });
});
4. Skydd mot algoritmförväxlingsattacker
Algoritmförväxling är en kritisk sårbarhet. Så här förhindrar du den:
- Specificera tillåtna algoritmer explicit: När du verifierar JWT:er, specificera explicit de tillåtna signeringsalgoritmerna. Förlita dig inte på att JWT-biblioteket automatiskt bestämmer algoritmen.
- Lita inte på
alg
-sidhuvudet: Lita aldrig blint påalg
-sidhuvudet i JWT:n. Validera det alltid mot en fördefinierad lista över tillåtna algoritmer. - Använd stark statisk typning (om möjligt): I språk som stöder statisk typning, tillämpa strikt typkontroll för nyckel- och algoritmparametrarna.
Exempel: Förhindra algoritmförväxling (Node.js med jsonwebtoken
)
const jwt = require('jsonwebtoken');
try {
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'] // Tillåt explicit endast RS256
});
console.log(decoded);
} catch (error) {
console.error('JWT validation failed:', error);
}
5. Implementera korrekt utgångstid och mekanismer för förnyelse av tokens
En tokens livslängd är en viktig säkerhetsaspekt:
- Använd kortlivade åtkomsttokens: Håll åtkomsttokens kortlivade (t.ex. 5-30 minuter). Detta begränsar effekten om en token komprometteras.
- Implementera refresh-tokens: Använd refresh-tokens för att få nya åtkomsttokens utan att användaren behöver autentisera sig på nytt. Refresh-tokens kan ha en längre livslängd men bör lagras säkert.
- Implementera rotation av refresh-tokens: Rotera refresh-tokens varje gång en ny åtkomsttoken utfärdas. Detta ogiltigförklarar den gamla refresh-token, vilket begränsar den potentiella skadan om en refresh-token komprometteras.
- Överväg sessionshantering: För känsliga applikationer, överväg att implementera sessionshantering på serversidan utöver JWT:er. Detta gör att du kan återkalla åtkomst mer granulärt.
6. Skydd mot tokenstöld
Att förhindra tokenstöld är avgörande:
- Implementera strikt Content Security Policy (CSP): Använd CSP för att förhindra XSS-attacker. CSP låter dig specificera vilka källor som får ladda resurser (skript, stilar, bilder, etc.) på din webbplats.
- Sanera användarinmatning: Sanera all användarinmatning för att förhindra XSS-attacker. Använd ett betrott HTML-saneringsbibliotek för att undkomma potentiellt skadliga tecken.
- Använd HTTPS: Använd alltid HTTPS för att kryptera kommunikationen mellan klienten och servern. Detta förhindrar angripare från att avlyssna nätverkstrafik och stjäla JWT:er.
- Implementera HSTS (HTTP Strict Transport Security): Använd HSTS för att instruera webbläsare att alltid använda HTTPS när de kommunicerar med din webbplats.
7. Övervakning och loggning
Effektiv övervakning och loggning är avgörande för att upptäcka och svara på säkerhetsincidenter:
- Logga utfärdande och validering av JWT: Logga alla händelser för utfärdande och validering av JWT, inklusive användar-ID, IP-adress och tidsstämpel.
- Övervaka misstänkt aktivitet: Övervaka ovanliga mönster, som flera misslyckade inloggningsförsök, JWT:er som används från olika platser samtidigt, eller snabba förfrågningar om förnyelse av tokens.
- Ställ in varningar: Ställ in varningar för att meddela dig om potentiella säkerhetsincidenter.
- Granska loggar regelbundet: Granska loggar regelbundet för att identifiera och utreda misstänkt aktivitet.
8. Hastighetsbegränsning (Rate Limiting)
Implementera hastighetsbegränsning för att förhindra brute-force-attacker och denial-of-service (DoS)-attacker:
- Begränsa inloggningsförsök: Begränsa antalet misslyckade inloggningsförsök från en enskild IP-adress eller ett användarkonto.
- Begränsa förfrågningar om förnyelse av tokens: Begränsa antalet förfrågningar om förnyelse av tokens från en enskild IP-adress eller ett användarkonto.
- Begränsa API-förfrågningar: Begränsa antalet API-förfrågningar från en enskild IP-adress eller ett användarkonto.
9. Håll dig uppdaterad
- Håll bibliotek uppdaterade: Uppdatera regelbundet dina JWT-bibliotek och beroenden för att patcha säkerhetssårbarheter.
- Följ bästa praxis för säkerhet: Håll dig informerad om de senaste bästa metoderna för säkerhet och sårbarheter relaterade till JWT:er.
- Utför säkerhetsgranskningar: Utför regelbundet säkerhetsgranskningar av din applikation för att identifiera och åtgärda potentiella sårbarheter.
Globala överväganden för JWT-säkerhet
När du implementerar JWT:er för globala applikationer, tänk på följande:
- Tidszoner: Se till att dina servrar är synkroniserade med en tillförlitlig tidskälla (t.ex. NTP) för att undvika problem med klockavvikelser som kan påverka JWT-validering, särskilt anspråken
exp
ochnbf
. Överväg att konsekvent använda UTC-tidsstämplar. - Dataskyddsförordningar: Var medveten om dataskyddsförordningar, som GDPR, CCPA och andra. Minimera mängden personuppgifter som lagras i JWT:er och säkerställ efterlevnad av relevanta regler. Kryptera känsliga anspråk om det behövs.
- Internationalisering (i18n): När du visar information från JWT-anspråk, se till att data är korrekt lokaliserat för användarens språk och region. Detta inkluderar att formatera datum, siffror och valutor på lämpligt sätt.
- Juridisk efterlevnad: Var medveten om eventuella juridiska krav relaterade till datalagring och överföring i olika länder. Se till att din JWT-implementering följer alla tillämpliga lagar och förordningar.
- Cross-Origin Resource Sharing (CORS): Konfigurera CORS korrekt för att tillåta din applikation att komma åt resurser från olika domäner. Detta är särskilt viktigt när du använder JWT:er för autentisering över olika tjänster eller applikationer.
Sammanfattning
JWT:er erbjuder ett bekvämt och effektivt sätt att hantera autentisering och auktorisering, men de introducerar också potentiella säkerhetsrisker. Genom att följa dessa bästa praxis kan du avsevärt minska risken för sårbarheter och säkerställa säkerheten för dina globala applikationer. Kom ihåg att hålla dig informerad om de senaste säkerhetshoten och uppdatera din implementering därefter. Att prioritera säkerhet genom hela JWT-livscykeln hjälper till att skydda dina användare och data från obehörig åtkomst.