JWT का इस्तेमाल बंद करें
(gist.github.com/samsch)- JWT उपयोगकर्ताओं को लॉग-इन स्थिति में बनाए रखने के लिए उपयुक्त नहीं है, और इस उद्देश्य के लिए सामान्य cookie session अधिक उपयुक्त है
- JWT स्पेसिफिकेशन लगभग 5 मिनट या उससे कम के short-lived token को ध्यान में रखकर बनाया गया है, जबकि session को इससे अधिक समय तक जीवित रहना पड़ता है
- सुरक्षित stateless authentication को व्यवहार में लाना कठिन है, और token को सुरक्षित रूप से संभालने के लिए अंततः किसी न किसी state store की आवश्यकता होती है
- केवल साधारण session token रखने वाला JWT, सामान्य session cookie की तुलना में कम दक्ष और कम लचीला है, और authentication जानकारी को localStorage या sessionStorage में संग्रहीत नहीं करना चाहिए
- जब कम समय के signed token की आवश्यकता हो, तो सुरक्षा के लिए डिज़ाइन किया गया PASETO बेहतर विकल्प है, लेकिन इसका उपयोग session के लिए नहीं करना चाहिए
मुख्य सारांश
- JWT का उपयोग उपयोगकर्ताओं को लॉग-इन स्थिति में बनाए रखने के लिए नहीं करना चाहिए; इस उद्देश्य के लिए सामान्य cookie session बेहतर साधन है
- JWT इस उद्देश्य के लिए डिज़ाइन नहीं किया गया था और सुरक्षित नहीं है, जबकि लॉग-इन session बनाए रखने के लिए नियमित cookie session अधिक उपयुक्त है
- संबंधित विषय के रूप में, JWT token सहित authentication credentials को localStorage या sessionStorage में संग्रहीत नहीं करना चाहिए
- इस विषय पर प्रस्तुतियाँ देखी जा सकती हैं, लेकिन CSRF सुरक्षा जैसे अन्य विषय अक्सर केवल संक्षेप में कवर किए जाते हैं, इसलिए उन्हें अलग स्रोतों से अलग से सीखना चाहिए
- वीडियो के अंत में बताए गए “वैध” JWT उपयोग के मामले भी बेहतर और अधिक सुरक्षित टूल से आसानी से संभाले जा सकते हैं, विशेष रूप से PASETO
JWT से बचना क्यों चाहिए
- JWT स्पेसिफिकेशन केवल लगभग 5 मिनट या उससे कम समय के बहुत short-lived token के लिए डिज़ाइन किया गया था, जबकि session को इससे अधिक लंबी अवधि चाहिए
- सुरक्षित stateless authentication संभव नहीं है, और token को सुरक्षित रूप से संभालने के लिए कुछ state अनिवार्य रूप से चाहिए
- यदि data store की आवश्यकता है, तो केवल कुछ token state संभालने के बजाय पूरा data संग्रहीत करना बेहतर है
- संबंधित समस्या पर http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/ में अधिक विस्तार से चर्चा की गई है
- वास्तव में कुछ applications JWT का इस तरह उपयोग करते हैं, लेकिन वे applications दोषपूर्ण हैं, इसलिए वही गलती दोहरानी नहीं चाहिए
- केवल साधारण session token संग्रहीत करने वाला JWT, सामान्य session cookie की तुलना में कम दक्ष और कम लचीला है, और कोई अतिरिक्त लाभ नहीं देता
- JWT स्पेसिफिकेशन स्वयं सुरक्षा विशेषज्ञों के बीच विश्वसनीय नहीं माना जाता, इसलिए इसे सुरक्षा और authentication से जुड़े उपयोगों से पूरी तरह बाहर रखना चाहिए
- मूल स्पेसिफिकेशन नकली token बनाने की अनुमति देता था, और इसमें अन्य गलतियाँ भी होने की संभावना है
- JWT परिवार के स्पेसिफिकेशन की समस्याओं पर JWT: The JSON Web Token standard is bad and everyone should avoid it में और गहराई से चर्चा की गई है
आपत्तियाँ
- “Google भी JWT का उपयोग करता है” वाली आपत्ति ब्राउज़र के user session पर लागू नहीं होती
- Google ब्राउज़र user session के लिए JWT का उपयोग नहीं करता; वह सामान्य cookie session का उपयोग करता है
- JWT का उपयोग केवल एक server या host की login session को दूसरे server या host की session तक पहुँचाने वाले Single Sign On ट्रांसपोर्ट माध्यम के रूप में किया जाता है
- यह उपयोग JWT के तर्कसंगत उपयोग-क्षेत्र में आता है
- Google के पास अधिक सुरक्षित JWT implementation बनाने और बनाए रखने के लिए security experts के संसाधन हैं
- Google का JWT व्यवहार में अन्य जगहों के JWT जैसा नहीं है
- “stateless बेहतर है” वाली आपत्ति सुरक्षित authentication की आवश्यकताओं से मेल नहीं खाती
- बहुत बड़े संसाधनों के बिना वास्तविक stateless authentication को सुरक्षित रूप से संचालित नहीं किया जा सकता
- संबंधित चर्चा के लिए Stateless is a lie देखा जा सकता है
- “मुझे session सेट करना नहीं आता” वाली समस्या अधिकांश web server framework के documentation और implementation से हल हो सकती है
- session तकनीक कोई नई चीज़ नहीं है, इसलिए session समझाने वाले लेख अक्सर कम दिखते हैं
- session implementation के documentation भर से भी configuration प्रक्रिया का पालन किया जा सकता है
- लगभग हर web server framework में session implementation शामिल होती है, और यदि वह default रूप से सक्रिय न भी हो तो आमतौर पर आसानी से सक्रिय की जा सकती है
- Express और अन्य Node.js framework अपने उच्च modularity और single-purpose स्वभाव के कारण कुछ हद तक अपवाद हैं
- Express में
express-sessionmiddleware और storage के अनुरूप store connector का उपयोग किया जा सकता है - Postgres, MySQL या यदि संभव हो तो SQLite के साथ
connect-session-knexउपयोग करने की सिफारिश की जाती है
अल्पकालिक token
- यदि किसी उपयोग के लिए कम अवधि वाला signed token चाहिए, तो सुरक्षा के लिए डिज़ाइन किया गया PASETO नामक बेहतर स्पेसिफिकेशन उपलब्ध है
- PASETO का उपयोग करने पर भी इसे session के लिए उपयोग नहीं करना चाहिए
session कैसे काम करता है
- session कैसे काम करता है, यह अधिक जानने के लिए joepie91 की gist देखना बेहतर है
2 टिप्पणियां
JWT टोकन encryption और DB query को कम करने का एक तरीका है; यह cookie authentication के ठीक विपरीत खड़ा कोई concept नहीं है। अगर JWT को secure cookie में store किया जाए, तो उसके चोरी होने का जोखिम legacy cookie authentication तरीके जैसा ही होता है
JWT को expired करने के लिए expiry list को manage करना performance के लिहाज़ से फ़ायदेमंद हो सकता है। सिर्फ expiry जानकारी को redis में query करने और सभी users के लिए DB query करने की लागत में फ़र्क होता है।
दसियों हज़ार बार 1 लाख member rows पर index-based query (legacy cookie तरीका)
vs
दसियों हज़ार बार redis में 50 expired entries की query (JWT immediate expire तरीका)
JWT के फ़ायदे हैं। बस छोटे पैमाने के environment में यह फ़र्क कम दिखाई देता है
Hacker News की राय
ज़रूरी संदर्भ गायब है: यह ब्राउज़र-आधारित user session की बात है
services के बीच communication में JWT कई मामलों में ठीक से इस्तेमाल किया जा सकता है
और जोड़ूँ तो, मैंने linked post का कुछ हिस्सा पढ़ा है, और उदाहरण के लिए https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba... जैसी post है। अगर JWT वाकई इतना भयानक रूप से असुरक्षित standard है, तो AWS STS के AssumeRoleWithWebIdentity को hack करने का तरीका प्रकाशित कर देना चाहिए, या प्रकाशित न करके Fortune 500 कंपनियों के production AWS accounts पर crypto miners चला देने चाहिए। अगर JWT इतना असुरक्षित है, तो जब सफल हो जाओ तो बताना /व्यंग्य
JWT का signing·encryption हिस्सा जटिल है, और आम JWT libraries भी अब जाकर ज़्यादातर संभली हैं, लेकिन पहले ऐसा नहीं था। बहुत-सी libraries
"none"algorithm स्वीकार करती थीं [1], और कुछ मामलों में public key को shared secret की तरह इस्तेमाल किया गया, जिससे attacker token forge कर सकता था [2]। linked post जिस complexity की आलोचना करती है, यह उसका सीधा नतीजा हैJWT कई बार user session में वह काम भी नहीं कर पाता जो चाहिए। अगर कहीं revoke list न रखी जाए तो इसे invalidate नहीं किया जा सकता। लेकिन अगर हर request पर identifier को revoke list से मिलाना ही है, तो opaque session ID इस्तेमाल करके हर request पर lookup कर लेना बेहतर है। हाँ, short-lived tokens और लगातार refresh का तरीका अपनाया जा सकता है, लेकिन वैसे भी stateful रहने वाले सामान्य applications में ऐसा करने की खास वजह नहीं है
लेकिन distributed systems या machine-to-machine communication में signed tokens उपयोगी हो सकते हैं, इस बात से मैं पूरी तरह सहमत हूँ। इन दोनों मामलों को मिलाना नहीं चाहिए
[1] https://nvd.nist.gov/vuln/detail/cve-2022-23540
[2] https://nvd.nist.gov/vuln/detail/CVE-2024-54150
अब कई भाषाओं की प्रमुख libraries में ज़्यादा sensible defaults आ गए हैं, इसलिए आजकल यह वास्तव में काफ़ी सुरक्षित हो गया है
अगर “इसे सही तरह पकड़कर इस्तेमाल करो तो यह सुरक्षित है” का मतलब अच्छी design है, तो वही बात X.509 जैसी चीज़ों पर भी लागू होगी
कई मामलों में बेहतर alternatives मौजूद हैं। standard session tokens या API keys ज़्यादातर बड़े websites में व्यापक रूप से इस्तेमाल होते हैं, और अधिकतर use cases में लगभग पूरी तरह fit बैठते हैं
इसका मतलब यह नहीं कि इन standards की कोई value ही नहीं है। सबसे अच्छी बात यह है कि यह ASN.1 encoding जैसी चीज़ों के बिना कुछ आदान-प्रदान करने का एक basic standard है, और ASN.1 ecosystem के tools बहुत fragile और buggy लगते हैं
उदाहरण के लिए, मुझे नहीं पता SAML का दुरुपयोग कैसे किया जाता है, लेकिन मैं यह जानता हूँ कि वह पूरे XML parser को attack surface बना देता है, इसलिए वह एक भयानक standard है। मैं security researcher नहीं हूँ, इसलिए XML parser में vulnerabilities ढूँढ़ना नहीं जानता, लेकिन इतना समझ सकता हूँ कि बड़ा attack surface बुरी बात है
JWT असुरक्षित है? क्या trusted RSA/public-key आधारित signing scheme इस्तेमाल करने पर भी? shared secret न होने पर भी?
यह दावा भी अजीब लगता है कि JWT बहुत लंबे समय तक जीवित रहता है। JWT की lifetime सीमित की जा सकती है और authentication authority के लिए refresh model रखा जा सकता है। cookie-based session इस्तेमाल करें तब भी आखिरकार कहीं न कहीं storage तो है ही। JWT को सिर्फ 5~15 मिनट के लिए valid बनाया जा सकता है, और 15 मिनट Entra सहित कई authorization systems के cache time जैसा ही है। 5 मिनट का token भी अगर refresh system हो तो browser में पर्याप्त रूप से काम कर सकता है
अंत में, मैं identity/authentication को application·API service से अलग रखना पसंद करता हूँ। इससे context को externalize किया जा सकता है, और हर request पर JWT process करने का तरीका कभी-कभी fail होने वाले shared cache/state systems से संभालना आसान होता है। signed token किसी ज्ञात authority के विरुद्ध signature verify कर सकता है
उसके अलावा signature cryptographically valid होती है। short lifetime रखकर हर JWT को हर बार verify किया जा सकता है
संदर्भ के लिए, OIDC tokens सब के सब JWT हैं
session और JWT revoke list की तुलना करें तो, JWT revoke list के पक्ष में भी तर्क है। JWT में सीमित expiry time होता है, इसलिए सिर्फ उन्हीं tokens की revoke list रखनी होती है जो अभी expired नहीं हुए हैं
circulation में मौजूद valid JWT की तुलना में revoked JWT शायद सिर्फ एक हिस्सा होंगे, इसलिए हर request पर बहुत छोटे dataset को ही देखना होगा
session इस्तेमाल करने पर valid sessions की सूची revoke list से कई orders of magnitude बड़ी हो सकती है, इसलिए stateful storage के साथ lookup cost और storage cost दोनों ज़्यादा हैं
और वैसे भी, post में JWT को stateless कहा गया है, लेकिन आम तौर पर ऐसा नहीं होता। आमतौर पर सिर्फ JWT verify नहीं किया जाता, बल्कि हर request पर matching identity object, यानी user details भी लाए जाते हैं, ताकि यह जाँचा जा सके कि user अभी भी active है या नहीं, और उसे वह action करने का अधिकार है या नहीं। per-user revoke list या
minimum_issued_atजैसे value का इस्तेमाल करके JWT केiatfield को verify किया जा सकता है। इससे “सभी devices से logout” वाला pattern भी संभव है, और उस action के लिए user काminimum_issued_atबस$NOWपर set करना होगा, जिससे पहले के सारे tokens revoke हो जाएँगे। अलग-अलग revoke list lookup की ज़रूरत नहीं होगीselectहै, जो 0~1 rows लौटाता है। ज़्यादातर मामलों में यह चिंता की बात नहीं हैयह लेख “क्यों” वाले ज़्यादातर हिस्सों के लिए दूसरे ब्लॉग पोस्टों के लिंक देता है, और वे ब्लॉग पोस्ट मोटे तौर पर इस बात से नाराज़ लगते हैं कि “अलग-अलग JWT token को invalidate नहीं किया जा सकता”
जब भी मैंने इसे implement किया है, सामान्य guideline यही रही है कि कहीं न कहीं invalidated nonce को check किया जाए, और ऐसा करने से उस लेख का दूसरा दावा भी हल हो जाता है
“JWT spec पर खुद security experts भरोसा नहीं करते” — इस दावे के लिए एक ब्लॉग पोस्ट से कहीं ज़्यादा सबूत चाहिए। और वह लेख ज़्यादातर खराब implementation को दोष देता दिखता है, जबकि किसी भी standard के साथ खराब implementation की समस्या रहती ही है
कुल मिलाकर, किसी random gist लिंक पर क्लिक करते हुए मैंने क्या उम्मीद की थी, पता नहीं
इसके अलावा, browser में कम lifetime वाले JWT आराम से इस्तेमाल किए जा सकते हैं, और agent को खुद refresh करने दिया जा सकता है। Azure Entra और कई दूसरे providers के साथ यह व्यवहार वास्तव में ऐसा ही होता है। JWT को काफ़ी छोटा, लगभग 5–15 मिनट का रखा जा सकता है, और
jtirevocation तक check की जा सकती हैJWT access authority को application/API system से अलग करने और reuse करने में बहुत उपयोगी हैं। यह attack surface को बस कहीं और ले जाना है, लेकिन एक भरोसेमंद तरीके से। पूरी दुनिया में SSH समेत कई जगह public key तरीका इस्तेमाल होता है। मैं shared secret या long-lived token का उपयोग नहीं करूँगा, लेकिन verified और known source से आए short-lived public-key-signed token आम तौर पर ठीक हैं
बल्कि असली समस्या कई बार API keys होती हैं। मुझे अभी हाल में यह implement करना पड़ा; मेरे मामले में API key को भी Bearer token जैसा बनाया गया, जिसमें छोटा
sak.prefix, उसके बाद identity हिस्सा (base64url UUID bytes), फिर secret value (base64url bytes) रखा। database में UUID और secret value से बना passphrase-grade salt+hash store किया। इसलिए बनाई गई API key को secret की तरह treat करना पड़ता है, और database में वह सिर्फ one-way रूप में रहती है, ताकि DB breach का मतलब सीधे auth breach न होफिर भी, अच्छी तरह implement किए गए JWT solution में समस्या आने की तुलना में API key leak होना कहीं ज़्यादा संभावित है
यह पोस्ट मुझे संयोग से दिखी, और क्योंकि मैंने पहले इस विषय पर बहुत काम किया था, इसलिए यह देखकर दिलचस्प लगा कि यह फिर चर्चा में है। लेकिन क्लिक करने पर पता चला कि लेखक ने मेरी कुछ सामग्री को link किया हुआ है। सचमुच बहुत पुरानी यादें ताज़ा हो गईं
खैर, मुझसे कहीं ज़्यादा समझदार लोग इस विषय को सालों से विस्तार से कवर करते आए हैं, लेकिन 2026 में भी मुझे लगता है कि web auth के लिए JWT गलत tool है। service-to-service उपयोग के लिए यह ठीक है, लेकिन अगर आपके पास विकल्प हो तो बस PASETO इस्तेमाल करना बेहतर है। यह बहुत-सी समस्याएँ हल कर देता है
https://www.paseto.io/
मैं अभी website पर notification push के लिए RabbitMQ जोड़ रहा हूँ। client कहाँ से क्या पढ़ सकता है, इसे नियंत्रित करने के लिए JWT auth इस्तेमाल कर रहा हूँ, और इसमें short lifetime तथा periodic token refresh रखे हैं
मुझे नहीं पता कि इस setup की सादगी के करीब कोई दूसरा configuration है भी या नहीं। बस valid session के लिए JWT token देने वाला एक endpoint जोड़ना होता है, और per-user permissions भी संभव हैं
JWT का उपयोग क्यों नहीं करना चाहिए, यह समझाने वाली linked posts में से एक, अच्छे से अच्छा कहें तो भी अजीब है
https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
सार यह है कि “कुछ libraries में bug थे”, और फिर वह libsodium लाकर सब कुछ खुद करने की सलाह देता है। इसे गंभीरता से लेना मुश्किल है; यह बेहूदा सलाह है। हर software में bugs होते हैं। Heartbleed के समय पूरा इंटरनेट हिल गया था, फिर भी हम आज TLS और OpenSSL का इस्तेमाल करते हैं
“JWT spec खास तौर पर बहुत कम lifetime वाले tokens, लगभग 5 मिनट या उससे कम, के लिए डिज़ाइन की गई थी” — यह बात मैं पहली बार सुन रहा हूँ, और इसके समर्थन में कोई आधार भी नहीं मिल रहा। RFC 7519 में ऐसा कोई दावा नहीं है
आम तौर पर JWT को auth cache की तरह इस्तेमाल किया जाता है। auth service से auth token मिलता है, और वही token दूसरी services के लिए authorization देता है
इसके कई फायदे हैं, लेकिन मुख्य बात यह है कि downstream services को auth database के साथ interact करने की ज़रूरत नहीं होती और न ही token issue करने का अधिकार चाहिए होता है। यह HMAC नहीं बल्कि RS256 इस्तेमाल करने की शर्त पर है। इसलिए अगर downstream service compromise हो भी जाए, तो वह उतना विनाशकारी नहीं होता जितना उस service का compromise होना जो auth database तक पहुँच सकती है
अगर token के अंदर sensitive data है तो JWE इस्तेमाल करना चाहिए, लेकिन तब हर इस्तेमाल पर private key रखने वाली internal service से token decrypt कराने की ज़रूरत पड़ती है, इसलिए यह बहुत अच्छा नहीं है
मैं जो structure अक्सर इस्तेमाल करता हूँ वह
{"id": (uuid), "scopes": ["scope:read/write"]}हैयह SPA के लिए भी काफ़ी अच्छा है, क्योंकि static site server resource serve करने से पहले public key से JWE verify कर सकता है। मेरा तरीका यह है कि static site को
/(scope)/pathफ़ॉर्म में compile किया जाए, ताकि जिन pages तक static service को access नहीं देना है, वे शुरू से ही serve न हों। यह तब बहुत उपयोगी है जब आप backend वाली capabilities या attackable internal service paths को user के सामने expose नहीं करना चाहते, जैसे admin panel में“backend access” के लिए JWT lifetime लगभग 5 मिनट रखता हूँ, और
/meजैसी चीज़ों को localStorage में cache करता हूँ, जब तक/refreshसाफ़ तौर पर localStorage cache हटाने के लिए न कहे। SPA application का request handler “refresh needed” detect करके token refresh कर देता हैमुझे लगता है कि इसकी बहुत-सी ज़िम्मेदारी node/next और Python libraries पर है। backend को strongly typed language में लिखता हूँ, और frontend को हमेशा precompiled static pages के रूप में बनाता हूँ। अभी का frontend setup VITE इस्तेमाल करता है, जहाँ landing pre-rendered pages के रूप में है और application सामान्य SPA है
यह सब ध्यान में रखने के बाद भी, मैं इस पूरे gist से सख़्ती से सहमत नहीं हूँ। JWT को जितना सुरक्षित बनाना चाहें, उतना बनाया जा सकता है
JWT ठीक है, और title थोड़ा सनसनीखेज़ लगता है
इसके बजाय कुछ बेहतर चर्चा के विषय हैं: encrypted values (symmetric या asymmetric), random लेकिन secret values, signed values (जिन्हें पढ़ा जा सकता है लेकिन बदला नहीं जा सकता) — इन्हें कब इस्तेमाल करना चाहिए; इन्हें कहाँ रखना चाहिए (memory, localStorage, cookie); और कैसे सुनिश्चित किया जाए कि ये values हमेशा के लिए न रहें, तथा क्या natural expiry time से पहले इन्हें revoke करने की ज़रूरत है