javascript एचटीएमएल 5 वेब ऐप में OAuth2 का उपयोग करना



oauth-2.0 (3)

मैं वर्तमान में जावास्क्रिप्ट में बनाया गया एक मोबाइल एप्लिकेशन विकसित करने के लिए ओएथ 2 के साथ प्रयोग कर रहा हूं जो केकपीएचपी एपीआई से बात करता है। यह देखने के लिए निम्न कोड पर एक नज़र डालें कि मेरा ऐप वर्तमान में कैसा दिखता है (कृपया ध्यान दें कि यह एक प्रयोग है, इसलिए गन्दा कोड, और क्षेत्रों में संरचना की कमी आदि ..)

var access_token,
     refresh_token;

var App = {
    init: function() {
        $(document).ready(function(){
            Users.checkAuthenticated();
        });
    }(),
    splash: function() {
        var contentLogin = '<input id="Username" type="text"> <input id="Password" type="password"> <button id="login">Log in</button>';
        $('#app').html(contentLogin);
    },
    home: function() {  
        var contentHome = '<h1>Welcome</h1> <a id="logout">Log out</a>';
        $('#app').html(contentHome);
    }
};

var Users = {
    init: function(){
        $(document).ready(function() {
            $('#login').live('click', function(e){
                e.preventDefault();
                Users.login();
            }); 
            $('#logout').live('click', function(e){
                e.preventDefault();
                Users.logout();
            });
        });
    }(),
    checkAuthenticated: function() {
        access_token = window.localStorage.getItem('access_token');
        if( access_token == null ) {
            App.splash();
        }
        else {
            Users.checkTokenValid(access_token);
        }
    },
    checkTokenValid: function(access_token){

        $.ajax({
            type: 'GET',
            url: 'http://domain.com/api/oauth/userinfo',
            data: {
                access_token: access_token
            },
            dataType: 'jsonp',
            success: function(data) {
                console.log('success');
                if( data.error ) {
                    refresh_token = window.localStorage.getItem('refresh_token');
                     if( refresh_token == null ) {
                         App.splash();
                     } else {
                         Users.refreshToken(refresh_token);
                    }
                } else {
                    App.home();
                }
            },
            error: function(a,b,c) {
                console.log('error');
                console.log(a,b,c);
                refresh_token = window.localStorage.getItem('refresh_token');
                 if( refresh_token == null ) {
                     App.splash();
                 } else {
                     Users.refreshToken(refresh_token);
                }
            }
        });

    },
    refreshToken: function(refreshToken){

        $.ajax({
            type: 'GET',
            url: 'http://domain.com/api/oauth/token',
            data: {
                grant_type: 'refresh_token',
                refresh_token: refreshToken,
                client_id: 'NTEzN2FjNzZlYzU4ZGM2'
            },
            dataType: 'jsonp',
            success: function(data) {
                if( data.error ) {
                    alert(data.error);
                } else {
                    window.localStorage.setItem('access_token', data.access_token);
                    window.localStorage.setItem('refresh_token', data.refresh_token);
                    access_token = window.localStorage.getItem('access_token');
                    refresh_token = window.localStorage.getItem('refresh_token');
                    App.home();
                }
            },
            error: function(a,b,c) {
                console.log(a,b,c);
            }
        });

    },
    login: function() {
        $.ajax({
            type: 'GET',
            url: 'http://domain.com/api/oauth/token',
            data: {
                grant_type: 'password',
                username: $('#Username').val(),
                password: $('#Password').val(),
                client_id: 'NTEzN2FjNzZlYzU4ZGM2'
            },
            dataType: 'jsonp',
            success: function(data) {
                if( data.error ) {
                    alert(data.error);
                } else {
                    window.localStorage.setItem('access_token', data.access_token);
                    window.localStorage.setItem('refresh_token', data.refresh_token);
                    access_token = window.localStorage.getItem('access_token');
                    refresh_token = window.localStorage.getItem('refresh_token');
                    App.home();
                }
            },
            error: function(a,b,c) {
                console.log(a,b,c);
            }
        });
    },
    logout: function() {
        localStorage.removeItem('access_token');
        localStorage.removeItem('refresh_token');
        access_token = window.localStorage.getItem('access_token');
        refresh_token = window.localStorage.getItem('refresh_token');
        App.splash();
    }
};

मेरे पास OAuth के कार्यान्वयन से संबंधित कई प्रश्न हैं:

1.) स्थानीय स्टोरेज में access_token को स्पष्ट रूप से संग्रहीत करना खराब अभ्यास है और मुझे कुकीज़ का उपयोग करना चाहिए। क्या कोई समझा सकता है क्यों? चूंकि यह अब तक सुरक्षित या कम सुरक्षित नहीं है, क्योंकि कुकी डेटा एन्क्रिप्ट नहीं किया जाएगा।

अद्यतन: इस प्रश्न के मुताबिक: स्थानीय स्टोरेज बनाम स्थानीय स्टोरेज में डेटा संग्रहित कुकीज़ केवल क्लाइंट-साइड पर उपलब्ध है और कुकीज़ के विपरीत कोई HTTP अनुरोध नहीं करता है, इसलिए मेरे लिए अधिक सुरक्षित लगता है, या कम से कम ऐसा प्रतीत नहीं होता है जहां तक ​​मैं बता सकता हूं कि कोई समस्या है!

2.) प्रश्न 1 से संबंधित, समाप्ति समय के लिए कुकी का उपयोग, मेरे लिए समान रूप से व्यर्थ होगा, जैसे कि आप कोड देखते हैं, उपयोगकर्ता की जानकारी प्राप्त करने के लिए ऐप पर एक अनुरोध किया जाता है, जो एक त्रुटि वापस करेगा यह सर्वर के अंत में समाप्त हो गया था, और एक refresh_token की आवश्यकता है। तो दोनों क्लाइंट और सर्वर पर समाप्ति समय होने के लाभों के बारे में सुनिश्चित न करें, जब सर्वर एक वास्तव में मायने रखता है।

3.) मैं ए के बिना रीफ्रेश टोकन कैसे प्राप्त करूं, इसे बाद में उपयोग करने के लिए मूल access_token के साथ संग्रहीत कर रहा हूं, और बी) क्लाइंट_आईडी भी संग्रहीत कर रहा है? मुझे बताया गया है कि यह एक सुरक्षा मुद्दा है, लेकिन मैं इन्हें बाद में कैसे उपयोग कर सकता हूं, लेकिन उन्हें केवल जेएस-एप ऐप में सुरक्षित रख सकता हूं? यह देखने के लिए ऊपर दिए गए कोड को फिर से देखें कि मैंने इसे अभी तक कैसे कार्यान्वित किया है।


Answer #1

ऐसा लगता है कि आप संसाधन मालिक पासवर्ड प्रमाण पत्र OAuth 2.0 प्रवाह का उपयोग कर रहे हैं उदाहरण के लिए उपयोगकर्ता नाम / पास सबमिट करना, टोकन को रीफ्रेश करने और टोकन रीफ्रेश करने के लिए सबमिट करना।

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

उस पृष्ठभूमि को ध्यान में रखते हुए, मुझे अपने प्रश्नों को संबोधित करने दें:

  1. या तो एक कुकी या लोकलस्टोर आपको पेज रीफ्रेश में स्थानीय दृढ़ता प्रदान करेगा। स्थानीय भंडारण में एक्सेस टोकन को संग्रहीत करने से आपको सीएसआरएफ हमलों के खिलाफ थोड़ा और सुरक्षा मिलती है क्योंकि यह स्वचालित रूप से कुकी की तरह सर्वर पर नहीं भेजा जाएगा। आपके क्लाइंट-साइड जावास्क्रिप्ट को इसे स्थानीय स्टोरेज से बाहर खींचने और प्रत्येक अनुरोध पर इसे प्रेषित करने की आवश्यकता होगी। मैं ओएथ 2 ऐप पर काम कर रहा हूं और क्योंकि यह एक पृष्ठ दृष्टिकोण है जो मैं नहीं करता; इसके बजाय मैं इसे स्मृति में रखता हूं।
  2. मैं सहमत हूं ... यदि आप एक कुकी में संग्रहित कर रहे हैं तो यह केवल समाप्ति के लिए है, समाप्ति के लिए नहीं, सर्वर टोकन की समयसीमा समाप्त होने पर त्रुटि के साथ प्रतिक्रिया दे रहा है। एकमात्र कारण यह है कि मैं सोच सकता हूं कि आप एक समाप्ति के साथ कुकी बना सकते हैं ताकि आप यह पता लगा सकें कि यह अनुरोध करने के बाद और त्रुटि प्रतिक्रिया के इंतजार के बिना समाप्त हो गया है या नहीं। बेशक आप उस ज्ञात समाप्ति समय को बचाकर स्थानीय भंडारण के साथ एक ही काम कर सकते हैं।
  3. यह मेरा पूरा विश्वास है कि मैं विश्वास करता हूं ... "मैं ए के बिना रीफ्रेश टोकन कैसे प्राप्त करूं, इसे बाद में उपयोग करने के लिए मूल access_token के साथ संग्रहीत करता हूं, और बी) क्लाइंट_आईडी भी संग्रहीत करता है"। दुर्भाग्यवश आप वास्तव में नहीं कर सकते ... जैसा कि उस प्रारंभिक टिप्पणी में उल्लेख किया गया है, ताज़ा टोकन क्लाइंट पक्ष होने से टोकन की सीमित आयु तक पहुंच प्रदान की गई सुरक्षा को अस्वीकार कर दिया जाता है। मैं अपने ऐप में क्या कर रहा हूं (जहां मैं किसी भी लगातार सर्वर-साइड सत्र स्थिति का उपयोग नहीं कर रहा हूं) निम्न है:
    • उपयोगकर्ता सर्वर पर उपयोगकर्ता नाम और पासवर्ड जमा करता है
    • इसके बाद सर्वर http://domain.com/api/oauth/token ऊपर आपके उदाहरण में, OAuth एंडपॉइंट पर उपयोगकर्ता नाम और पासवर्ड अग्रेषित करता है, और पहुंच टोकन और टोकन रीफ्रेश दोनों प्राप्त करता है।
    • सर्वर रीफ्रेश टोकन को एन्क्रिप्ट करता है और इसे कुकी में सेट करता है (केवल HTTP होना चाहिए)
    • सर्वर केवल स्पष्ट पाठ (एक JSON प्रतिक्रिया में) में पहुंच टोकन के साथ प्रतिक्रिया करता है और एन्क्रिप्टेड HTTP केवल कुकी
    • क्लाइंट-साइड जावास्क्रिप्ट अब एक्सेस टोकन को पढ़ और उपयोग कर सकता है (स्थानीय स्टोरेज में स्टोर या जो भी हो
    • जब एक्सेस टोकन समाप्त हो जाता है, तो ग्राहक एक नए टोकन के लिए सर्वर से अनुरोध करता है (OAuth सर्वर नहीं बल्कि ऐप होस्ट करने वाला सर्वर)
    • सर्वर, इसे बनाए गए एन्क्रिप्टेड HTTP केवल कुकी प्राप्त करता है, इसे रीफ्रेश टोकन प्राप्त करने के लिए डिक्रिप्ट करता है, एक नया एक्सेस टोकन अनुरोध करता है और अंत में प्रतिक्रिया में नया एक्सेस टोकन देता है।

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

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

एक और विकल्प केवल रीफ्रेश टोकन का अनुरोध करने के लिए नहीं है (सुनिश्चित नहीं है कि यह ओएथ 2 कार्यान्वयन के साथ एक विकल्प है जिसके साथ आप काम कर रहे हैं; रीफ्रेश टोकन स्पेक प्रति वैकल्पिक है) और जब यह समाप्त हो जाता है तो लगातार पुनः प्रमाणीकृत होता है।

उम्मीद है की वो मदद करदे!


Answer #2

शुद्ध ग्राहक पक्ष के लिए केवल दृष्टिकोण, यदि आपके पास मौका है, तो "संसाधन प्रवाह प्रवाह" का उपयोग करने के बजाय "संसाधन प्रवाह प्रवाह" का उपयोग करने का प्रयास करें। आपको प्रतिक्रिया के हिस्से के रूप में ताज़ा टोकन प्राप्त नहीं होता है।

  1. जब उपयोगकर्ता एक्सेस पेज जावास्क्रिप्ट स्थानीय स्टोरेज में access_token के लिए चेक करता है और यह expires_in जांचता है
  2. यदि अनुपलब्ध या समाप्त हो गया है तो एप्लिकेशन नए टैब को खोलता है और उपयोगकर्ता को लॉगिन पेज पर रीडायरेक्ट करता है, सफल लॉगिन उपयोगकर्ता को एक्सेस टोकन के साथ रीडायरेक्ट किया जाता है जिसे केवल क्लाइंट पक्ष को संभाला जाता है और रीडायरेक्ट पेज के साथ स्थानीय स्टोरेज में संरक्षित किया जाता है
  3. मुख्य पृष्ठ में स्थानीय संग्रहण में पहुंच टोकन पर मतदान तंत्र हो सकता है और जैसे ही उपयोगकर्ता लॉग इन होता है (रीडायरेक्ट पृष्ठ टोकन को स्टोरेज में सहेजता है) पृष्ठ प्रक्रिया सामान्य रूप से।

उपर्युक्त दृष्टिकोण में पहुंच टोकन लंबे समय तक जीवित होना चाहिए (उदाहरण के लिए 1 वर्ष)। यदि लंबी जीवित टोकन के साथ कोई चिंता है तो आप निम्न चाल का उपयोग कर सकते हैं।

  1. जब उपयोगकर्ता एक्सेस पेज जावास्क्रिप्ट स्थानीय स्टोरेज में access_token के लिए चेक करता है और यह expires_in जांचता है
  2. यदि गुम या समाप्त हो गया है तो एप्लिकेशन छिपी आईफ्रेम खुलता है और उपयोगकर्ता को लॉगिन करने का प्रयास करता है। आम तौर पर ऑथ वेबसाइट में उपयोगकर्ता कुकी होती है और ग्राहक वेबसाइट को स्टोर प्रदान करती है, इसलिए लॉगिन स्वचालित रूप से होता है और आईफ़्रेम के अंदर स्क्रिप्ट स्टोरेज में टोकन को पॉप्युलेट करेगा
  3. क्लाइंट का मुख्य पृष्ठ access_token और टाइमआउट पर मतदान तंत्र सेट करता है। यदि इस छोटी अवधि के दौरान access_token भंडारण में नहीं आती है, तो इसका मतलब है कि हमें नया टैब खोलने और गति में सामान्य लागू प्रवाह सेट करने की आवश्यकता है

Answer #3

पूरी तरह से सुरक्षित होने का एकमात्र तरीका एक्सेस टोकन क्लाइंट पक्ष को स्टोर नहीं करना है। आपके ब्राउज़र पर (भौतिक) पहुंच वाला कोई भी व्यक्ति आपके टोकन प्राप्त कर सकता है।

1) न तो एक अच्छा समाधान होने का आपका मूल्यांकन सटीक है।

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

3) एक नया टोकन प्राप्त करने के लिए ताजा टोकन प्राप्त करने के लिए ओथ वर्कफ़्लो करने की आवश्यकता होगी। OAuth के कार्य करने के लिए क्लाइंट_आईडी एक विशिष्ट डोमेन से जुड़ा हुआ है।

ओथ टोकन को बनाए रखने के लिए सबसे सुरक्षित तरीका सर्वर साइड कार्यान्वयन होगा।





oauth-2.0