node.js - जेडब्ल्यूटी(जेएसओएन वेब टोकन) समाप्ति की स्वचालित लम्बाई




api security (6)

jwt-autorefresh

यदि आप नोड (रिएक्ट / रेडक्स / यूनिवर्सल जेएस) का उपयोग कर रहे हैं तो आप npm i -S jwt-autorefresh इंस्टॉल कर सकते हैं।

यह लाइब्रेरी शेड्यूल जेडब्ल्यूटी टोकन के रीफ्रेश को एक्सेस करने के लिए टोकन की समाप्ति से पहले सेकेंड की गणना की गई थी (टोकन में एन्कोड किए गए एक्सप दावे के आधार पर)। इसमें एक व्यापक परीक्षण सूट है और यह सुनिश्चित करने के लिए कुछ स्थितियों के लिए जांच करता है कि किसी भी अजीब गतिविधि के साथ आपके पर्यावरण से गलत कॉन्फ़िगरेशन के बारे में एक वर्णनात्मक संदेश है।

पूर्ण उदाहरण कार्यान्वयन

import autorefresh from 'jwt-autorefresh'

/** Events in your app that are triggered when your user becomes authorized or deauthorized. */
import { onAuthorize, onDeauthorize } from './events'

/** Your refresh token mechanism, returning a promise that resolves to the new access tokenFunction (library does not care about your method of persisting tokens) */
const refresh = () => {
  const init =  { method: 'POST'
                , headers: { 'Content-Type': `application/x-www-form-urlencoded` }
                , body: `refresh_token=${localStorage.refresh_token}&grant_type=refresh_token`
                }
  return fetch('/oauth/token', init)
    .then(res => res.json())
    .then(({ token_type, access_token, expires_in, refresh_token }) => {
      localStorage.access_token = access_token
      localStorage.refresh_token = refresh_token
      return access_token
    })
}

/** You supply a leadSeconds number or function that generates a number of seconds that the refresh should occur prior to the access token expiring */
const leadSeconds = () => {
  /** Generate random additional seconds (up to 30 in this case) to append to the lead time to ensure multiple clients dont schedule simultaneous refresh */
  const jitter = Math.floor(Math.random() * 30)

  /** Schedule autorefresh to occur 60 to 90 seconds prior to token expiration */
  return 60 + jitter
}

let start = autorefresh({ refresh, leadSeconds })
let cancel = () => {}
onAuthorize(access_token => {
  cancel()
  cancel = start(access_token)
})

onDeauthorize(() => cancel())

अस्वीकरण: मैं रखरखाव कर रहा हूँ

मैं अपने नए आरईएसटी एपीआई में जेडब्ल्यूटी-आधारित प्रमाणीकरण को लागू करना चाहता हूं। लेकिन चूंकि समाप्ति टोकन में सेट की गई है, क्या यह स्वचालित रूप से इसे लंबे समय तक संभव बनाना संभव है? मैं नहीं चाहता कि उपयोगकर्ताओं को प्रत्येक एक्स मिनट के बाद साइन इन करने की आवश्यकता हो, यदि वे सक्रिय रूप से उस अवधि में एप्लिकेशन का उपयोग कर रहे थे। यह एक विशाल यूएक्स असफल होगा।

लेकिन समाप्ति को लंबे समय तक एक नया टोकन बनाता है (और पुराना अभी भी समाप्त होने तक वैध है)। और प्रत्येक अनुरोध के बाद मुझे मूर्खतापूर्ण लगता है के बाद एक नया टोकन उत्पन्न करना। सुरक्षा समस्या की तरह लगता है जब एक से अधिक टोकन एक ही समय में मान्य होते हैं। बेशक मैं ब्लैकलिस्ट का उपयोग कर पुराने इस्तेमाल किए गए व्यक्ति को अमान्य कर सकता हूं लेकिन मुझे टोकन स्टोर करने की आवश्यकता होगी। और जेडब्ल्यूटी के लाभों में से कोई भी भंडारण नहीं है।

मैंने पाया कि कैसे Auth0 इसे हल किया। वे न केवल जेडब्ल्यूटी टोकन का उपयोग करते हैं बल्कि एक ताज़ा टोकन भी उपयोग करते हैं: https://docs.auth0.com/refresh-token

लेकिन फिर, इसे लागू करने के लिए (Auth0 के बिना) मुझे ताज़ा टोकन स्टोर करने और उनकी समाप्ति को बनाए रखने की आवश्यकता होगी। तब असली लाभ क्या है? क्यों न केवल एक टोकन (जेडब्ल्यूटी नहीं) और सर्वर पर समाप्ति रखें?

क्या अन्य विकल्प हैं? इस परिदृश्य के लिए जेडब्ल्यूटी का उपयोग नहीं कर रहा है?


अच्छा सवाल- और प्रश्न में जानकारी की धनराशि है।

आलेख ताज़ा टोकन: उन्हें कब उपयोग करें और वे जेडब्ल्यूटी के साथ कैसे बातचीत करते हैं इस परिदृश्य के लिए एक अच्छा विचार देता है। कुछ बिंदु हैं: -

  • रीफ्रेश टोकन एक नया एक्सेस टोकन प्राप्त करने के लिए आवश्यक जानकारी लेते हैं।
  • रीफ्रेश टोकन भी समाप्त हो सकते हैं लेकिन लंबे समय तक जीवित हैं।
  • रीफ्रेश टोकन आमतौर पर सख्त भंडारण आवश्यकताओं के अधीन होते हैं ताकि यह सुनिश्चित किया जा सके कि वे लीक नहीं हैं।
  • उन्हें प्राधिकरण सर्वर द्वारा भी ब्लैकलिस्ट किया जा सकता है।

इसके अलावा auth0/angular-jwt पर एक नज़र डालें

वेब एपीआई के लिए। एएसपी .NET वेब एपीआई 2, और ओविन का उपयोग कर AngularJS ऐप में OAuth रीफ्रेश टोकन को सक्षम करें पढ़ें


इस मामले में जहां आप स्वयं को ऑथ करते हैं (यानी Auth0 जैसे प्रदाता का उपयोग न करें), निम्न कार्य कर सकते हैं:

  1. अपेक्षाकृत कम समाप्ति के साथ जेडब्ल्यूटी टोकन जारी करें, 15 मिनट कहते हैं।
  2. आवेदन किसी टोकन की आवश्यकता वाले लेनदेन से पहले टोकन समाप्ति तिथि जांचता है (टोकन में समाप्ति तिथि होती है)। यदि टोकन की समयसीमा समाप्त हो गई है, तो यह पहले एपीआई को टोकन 'रीफ्रेश' करने के लिए कहता है (यह यूएक्स को पारदर्शी रूप से किया जाता है)।
  3. एपीआई टोकन रीफ्रेश अनुरोध प्राप्त करता है, लेकिन पहले उपयोगकर्ता डेटाबेस को जांचता है कि उस उपयोगकर्ता प्रोफ़ाइल के विरुद्ध 'reauth' ध्वज सेट किया गया है (टोकन में उपयोगकर्ता आईडी हो सकती है)। यदि ध्वज मौजूद है, तो टोकन रीफ्रेश अस्वीकार कर दिया जाता है, अन्यथा एक नया टोकन जारी किया जाता है।
  4. दोहराएँ।

डेटाबेस बैकएंड में 'reauth' ध्वज सेट किया जाएगा, उदाहरण के लिए, उपयोगकर्ता ने अपना पासवर्ड रीसेट कर दिया है। जब उपयोगकर्ता अगली बार लॉग इन करता है तो ध्वज हटा दिया जाता है।

इसके अलावा, मान लीजिए कि आपके पास एक नीति है जिसके द्वारा उपयोगकर्ता को हर 72 घंटे में कम से कम एक बार लॉगिन करना होगा। उस स्थिति में, आपका एपीआई टोकन रीफ्रेश लॉजिक उपयोगकर्ता डेटाबेस से उपयोगकर्ता की अंतिम लॉगिन तिथि भी जांचता है और उस आधार पर टोकन रीफ्रेश को अस्वीकार / अनुमति देता है।


बैकएंड में रीस्टफुल एपिस के साथ हमारे एप्लिकेशन को HTML5 पर ले जाने पर मैं चारों ओर घूम रहा था। जिस समाधान के साथ मैं आया था वह था:

  1. क्लाइंट को सफल लॉगिन पर 30 मिनट (या सामान्य सर्वर साइड सत्र समय जो भी) के सत्र समय के साथ एक टोकन के साथ जारी किया जाता है।
  2. क्लाइंट-साइड टाइमर को अपने समाप्ति समय से पहले टोकन को नवीनीकृत करने के लिए सेवा कॉल करने के लिए बनाया गया है। नया टोकन भविष्य की कॉल में मौजूदा को प्रतिस्थापित करेगा।

जैसा कि आप देख सकते हैं, यह अक्सर ताज़ा टोकन अनुरोधों को कम करता है। यदि नवीनीकरण टोकन कॉल ट्रिगर होने से पहले उपयोगकर्ता ब्राउज़र / ऐप बंद कर देता है, तो पिछले टोकन समय पर समाप्त हो जाएगा और उपयोगकर्ता को फिर से लॉगिन करना होगा।

उपयोगकर्ता निष्क्रियता को पूरा करने के लिए एक और जटिल रणनीति लागू की जा सकती है (उदाहरण के लिए एक खोला ब्राउज़र टैब उपेक्षित)। उस स्थिति में, नवीनीकृत टोकन कॉल में अपेक्षित समाप्ति समय शामिल होना चाहिए जो परिभाषित सत्र समय से अधिक नहीं होनी चाहिए। आवेदन के अनुसार अंतिम उपयोगकर्ता बातचीत का ट्रैक रखना होगा।

मुझे लंबी समाप्ति को निर्धारित करने के विचार को पसंद नहीं है इसलिए यह दृष्टिकोण देशी अनुप्रयोगों के साथ अच्छी तरह से काम नहीं कर सकता है, जिसके लिए कम प्रमाणीकरण की आवश्यकता होती है।


मैंने टोकन डेटा में एक चर जोड़कर इस समस्या को हल किया:

softexp - I set this to 5 mins (300 seconds)

उपयोगकर्ता को फिर से लॉगिन करने के लिए मजबूर होने से पहले मैं अपने वांछित समय पर expiresIn विकल्प सेट करता expiresIn । मेरा 30 मिनट तक सेट है। यह softexp के मूल्य से अधिक होना चाहिए।

जब मेरा क्लाइंट साइड ऐप सर्वर एपीआई (जहां टोकन आवश्यक है, उदाहरण के लिए ग्राहक सूची पृष्ठ) के लिए अनुरोध भेजता है, तो सर्वर जांचता है कि जमा टोकन अभी भी मान्य है या नहीं, इसकी मूल समाप्ति (समाप्ति) मान पर आधारित है। यदि यह मान्य नहीं है, तो सर्वर इस त्रुटि के लिए विशेष रूप से स्थिति के साथ प्रतिक्रिया देगा, उदाहरण के लिए। INVALID_TOKEN

यदि टोकन अभी भी expiredIn मान के आधार पर मान्य है, लेकिन यह पहले से ही softexp मान से अधिक है, तो सर्वर इस त्रुटि के लिए एक अलग स्थिति के साथ प्रतिक्रिया देगा, उदाहरण के लिए। EXPIRED_TOKEN :

(Math.floor(Date.now() / 1000) > decoded.softexp)

क्लाइंट साइड पर, यदि इसे EXPIRED_TOKEN प्रतिक्रिया मिली है, तो उसे सर्वर पर नवीनीकरण अनुरोध भेजकर स्वचालित रूप से टोकन को नवीनीकृत करना चाहिए। यह उपयोगकर्ता के लिए पारदर्शी है और स्वचालित रूप से क्लाइंट ऐप का ख्याल रखा जा रहा है।

सर्वर में नवीनीकरण विधि को जांचना चाहिए कि टोकन अभी भी मान्य है या नहीं:

jwt.verify(token, secret, (err, decoded) => {})

सर्वर उपरोक्त विधि में विफल होने पर टोकन को नवीनीकृत करने से इंकार कर देगा।


मैंने वास्तव में एपीआई के लिए क्लाइंट लाइब्रेरी बनाने के लिए गुज़ल क्लाइंट का उपयोग करके इसे PHP में कार्यान्वित किया, लेकिन अवधारणा को अन्य प्लेटफ़ॉर्म के लिए काम करना चाहिए।

असल में, मैं दो टोकन जारी करता हूं, एक छोटा (5 मिनट) एक और एक लंबा जो एक सप्ताह के बाद समाप्त हो जाता है। क्लाइंट लाइब्रेरी छोटे टोकन के एक ताज़ा करने का प्रयास करने के लिए मिडलवेयर का उपयोग करती है अगर उसे कुछ अनुरोध के लिए 401 प्रतिक्रिया प्राप्त होती है। इसके बाद यह फिर से मूल अनुरोध का प्रयास करेगा और यदि रीफ्रेश करने में सक्षम था, तो उपयोगकर्ता को पारदर्शी रूप से सही प्रतिक्रिया मिलती है। अगर यह असफल रहा, तो यह केवल उपयोगकर्ता को 401 भेज देगा।

यदि छोटा टोकन समाप्त हो गया है, लेकिन अभी भी प्रामाणिक है और लंबा टोकन मान्य और प्रामाणिक है, तो यह उस सेवा पर एक विशेष अंतराल का उपयोग करके छोटे टोकन को रीफ्रेश करेगा जो लंबे टोकन प्रमाणीकृत करता है (यह केवल एक चीज है जिसका उपयोग किया जा सकता है)। इसके बाद यह एक नया लंबा टोकन प्राप्त करने के लिए छोटे टोकन का उपयोग करेगा, जिससे हर बार इसे छोटे टोकन को रीफ्रेश करने पर एक और सप्ताह तक विस्तारित किया जाएगा।

यह दृष्टिकोण हमें 5 मिनट के भीतर पहुंच को निरस्त करने की इजाजत देता है, जो टोकन की ब्लैकलिस्ट स्टोर किए बिना हमारे उपयोग के लिए स्वीकार्य है।

देर से संपादन: मेरे सिर में ताजा होने के बाद इस महीने को दोबारा पढ़ना, मुझे यह इंगित करना चाहिए कि छोटे टोकन को रीफ्रेश करते समय आप एक्सेस को निरस्त कर सकते हैं क्योंकि इससे अधिक महंगी कॉल के अवसर मिलते हैं (उदाहरण के लिए डेटाबेस को कॉल करने के लिए उपयोगकर्ता को कॉल करें या नहीं आपकी सेवा के लिए प्रत्येक कॉल पर इसके भुगतान के बिना) प्रतिबंधित कर दिया गया है।





jwt