हम एक एपीआई का खुलासा कर रहे हैं जिसे भागीदार केवल उन डोमेन पर उपयोग कर सकते हैं जिन्हें उन्होंने हमारे साथ पंजीकृत किया है। इसकी सामग्री आंशिक रूप से सार्वजनिक है (लेकिन अधिमानतः केवल उन डोमेन पर दिखाया जाना है जिन्हें हम जानते हैं), लेकिन हमारे उपयोगकर्ताओं के लिए अधिकतर निजी है। इसलिए:
क्या दिखाया गया है यह निर्धारित करने के लिए , हमारे उपयोगकर्ता को हमारे साथ लॉग इन करना होगा, लेकिन इसे अलग से संभाला जाएगा।
यह निर्धारित करने के लिए कि डेटा कहां दिखाया गया है, एक सार्वजनिक एपीआई कुंजी का उपयोग उन डोमेन तक पहुंच को सीमित करने के लिए किया जाता है जिन्हें हम जानते हैं, और यह सुनिश्चित करने के लिए कि निजी उपयोगकर्ता डेटा सीएसआरएफ के लिए असुरक्षित नहीं है ।
यह API कुंजी वास्तव में किसी को भी दिखाई देती है, हम अपने साथी को किसी अन्य तरीके से प्रमाणित नहीं करते हैं, और हमें REFERER की आवश्यकता नहीं है । फिर भी, यह सुरक्षित है:
जब हमारा get-csrf-token.js?apiKey=abc123
अनुरोध है:
abc123
डेटाबेस में कुंजी देखें और उस कुंजी के लिए मान्य डोमेन की एक सूची प्राप्त करें।
CSRF सत्यापन कुकी के लिए देखें। यदि यह मौजूद नहीं है, तो एक सुरक्षित यादृच्छिक मान उत्पन्न करें और इसे केवल HTTP- सत्र सत्र में रखें। यदि कुकी मौजूद थी, तो मौजूदा यादृच्छिक मान प्राप्त करें।
एपीआई कुंजी से सीएसआरएफ टोकन और कुकी से यादृच्छिक मूल्य बनाएं, और इस पर हस्ताक्षर करें । (सर्वर पर टोकन की सूची रखने के बजाय, हम मूल्यों पर हस्ताक्षर कर रहे हैं। दोनों मान हस्ताक्षरित टोकन में पठनीय होंगे, यह ठीक है।)
कैश्ड नहीं होने के लिए प्रतिक्रिया सेट करें, कुकी जोड़ें, और एक स्क्रिप्ट लौटाएं जैसे:
var apiConfig = apiConfig || {};
if(document.domain === 'expected-domain.com'
|| document.domain === 'www.expected-domain.com') {
apiConfig.csrfToken = 'API key, random value, signature';
// Invoke a callback if the partner wants us to
if(typeof apiConfig.fnInit !== 'undefined') {
apiConfig.fnInit();
}
} else {
alert('This site is not authorised for this API key.');
}
टिप्पणियाँ:
उपरोक्त एक सर्वर साइड स्क्रिप्ट को अनुरोध को रोकने से नहीं रोकता है, लेकिन केवल यह सुनिश्चित करता है कि यदि ब्राउज़र द्वारा अनुरोध किया गया है तो डोमेन मेल खाता है।
जावास्क्रिप्ट के लिए एक ही मूल नीति सुनिश्चित करता है कि एक ब्राउज़र को लोड और फिर जावास्क्रिप्ट स्रोत का निरीक्षण करने के एक्सएचआर (अजाक्स) का उपयोग नहीं कर सकते हैं। इसके बजाय, एक नियमित ब्राउज़र केवल <script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">
(या एक गतिशील समतुल्य) का उपयोग करके इसे लोड कर सकता है , और फिर कोड चलाएगा। बेशक, आपके सर्वर को उत्पन्न जावास्क्रिप्ट के लिए क्रॉस-ओरिजिनल रिसोर्स शेयरिंग और न ही JSONP का समर्थन नहीं करना चाहिए ।
एक ब्राउज़र स्क्रिप्ट document.domain
उपरोक्त स्क्रिप्ट को लोड करने से पहले मूल्य बदल सकती है । लेकिन इसके साथ ही मूल नीति केवल द्वारा डोमेन को छोटा करने के लिए अनुमति देता है को हटाने उपसर्गों, को फिर से लिखने की तरह subdomain.example.com
करने के लिए बस example.com
, या myblog.wordpress.com
करने के लिए wordpress.com
, या भी कुछ ब्राउज़रों में bbc.co.uk
करने के लिए co.uk
।
यदि कुछ सर्वर साइड स्क्रिप्ट का उपयोग करके जावास्क्रिप्ट फ़ाइल प्राप्त की जाती है तो सर्वर को कुकी भी मिल जाएगी। हालाँकि, एक तृतीय पक्ष सर्वर उपयोगकर्ता के ब्राउज़र सहयोगी नहीं बना सकता है जो हमारे डोमेन के लिए कुकी है। इसलिए, एक सर्वर साइड स्क्रिप्ट का उपयोग करके लाए गए CSRF टोकन और सत्यापन कुकी का उपयोग केवल बाद के सर्वर साइड कॉल द्वारा किया जा सकता है, न कि किसी ब्राउज़र में। हालांकि, ऐसे सर्वर साइड कॉल में उपयोगकर्ता कुकी शामिल नहीं होगी, और इसलिए केवल सार्वजनिक डेटा प्राप्त कर सकते हैं। यह वही डेटा है जो सर्वर साइड स्क्रिप्ट सीधे भागीदार की वेबसाइट से खुरच सकता है।
जब कोई उपयोगकर्ता लॉग इन करता है, तो आपको जो भी पसंद हो, उसमें कुछ उपयोगकर्ता कुकी सेट करें। (जावास्क्रिप्ट का अनुरोध करने से पहले उपयोगकर्ता पहले ही लॉग इन कर सकता है।)
सर्वर (GET और JSONP अनुरोध सहित) के बाद के सभी एपीआई अनुरोध में CSRF टोकन, CSRF सत्यापन कुकी और (यदि लॉग ऑन है) उपयोगकर्ता कुकी शामिल होनी चाहिए। यदि अनुरोध पर भरोसा किया जाए तो सर्वर अब यह निर्धारित कर सकता है:
एक मान्य CSRF टोकन की उपस्थिति सुनिश्चित करता है कि जावास्क्रिप्ट को अपेक्षित डोमेन से लोड किया गया था, अगर एक ब्राउज़र द्वारा लोड किया गया है।
सीएसआरएफ टोकन की वैधता कुकी के बिना उपस्थिति फर्जीवाड़े को इंगित करती है।
CSRF टोकन और CSRF सत्यापन कुकी दोनों की उपस्थिति कुछ भी सुनिश्चित नहीं करती है: यह या तो जाली सर्वर साइड अनुरोध हो सकता है, या ब्राउज़र से मान्य अनुरोध हो सकता है। (यह असमर्थित डोमेन से बने ब्राउज़र से अनुरोध नहीं हो सकता है।)
उपयोगकर्ता कुकी की उपस्थिति सुनिश्चित करता है कि उपयोगकर्ता लॉग ऑन है, लेकिन यह सुनिश्चित नहीं करता है कि उपयोगकर्ता दिए गए भागीदार का सदस्य है, और न ही उपयोगकर्ता सही वेबसाइट देख रहा है।
CSRF सत्यापन कुकी के बिना उपयोगकर्ता कुकी की उपस्थिति जालसाजी को इंगित करती है।
उपयोगकर्ता कुकी की उपस्थिति एक ब्राउज़र के माध्यम से वर्तमान अनुरोध को सुनिश्चित करती है। (यह मानते हुए एक उपयोगकर्ता एक अज्ञात वेबसाइट पर अपने क्रेडेंशियल दर्ज नहीं होता है, और यह सोचते हैं कि हम कुछ सर्वर साइड अनुरोध करने के लिए अपने स्वयं के क्रेडेंशियल्स का उपयोग उपयोगकर्ताओं के बारे में परवाह नहीं है।) हम तो भी CSRF सत्यापन कुकी है, तो उस CSRF सत्यापन कुकी था ब्राउज़र का उपयोग करके भी प्राप्त किया गया। इसके बाद, हम यदि भी , एक CSRF वैध हस्ताक्षर के साथ टोकन है औरCSRF सत्यापन कुकी में यादृच्छिक संख्या उस CSRF टोकन से मेल खाती है, फिर उस टोकन के लिए जावास्क्रिप्ट भी उसी बहुत पहले अनुरोध के दौरान प्राप्त की गई थी जिसके दौरान CSRF कुकी सेट की गई थी, इसलिए एक ब्राउज़र का उपयोग भी किया गया था। इसके बाद यह भी बताया गया है कि टोकन सेट होने से पहले उपरोक्त जावास्क्रिप्ट कोड निष्पादित किया गया था, और उस समय डोमेन दिए गए एपीआई कुंजी के लिए मान्य था।
तो: सर्वर अब हस्ताक्षरित टोकन से सुरक्षित रूप से एपीआई कुंजी का उपयोग कर सकता है।
यदि किसी भी बिंदु पर सर्वर अनुरोध पर भरोसा नहीं करता है, तो एक 403 निषिद्ध वापस आ जाता है। विजेट उपयोगकर्ता को एक चेतावनी दिखा कर इसका जवाब दे सकता है।
CSRF सत्यापन कुकी पर हस्ताक्षर करने की आवश्यकता नहीं है, क्योंकि हम हस्ताक्षरित CSRF टोकन से इसकी तुलना कर रहे हैं। कुकी पर हस्ताक्षर नहीं करने से प्रत्येक HTTP अनुरोध कम हो जाता है, और सर्वर सत्यापन थोड़ा तेज हो जाता है।
उत्पन्न CSRF टोकन अनिश्चित काल के लिए वैध है, लेकिन केवल सत्यापन कुकी के साथ संयोजन में, इसलिए प्रभावी रूप से ब्राउज़र बंद होने तक।
हम टोकन के हस्ताक्षर के जीवनकाल को सीमित कर सकते हैं। जब उपयोगकर्ता लॉग आउट करता है, तो हम OWASP अनुशंसा को पूरा करने के लिए CSRF सत्यापन कुकी को हटा सकते हैं । और प्रति-उपयोगकर्ता यादृच्छिक संख्या को कई भागीदारों के बीच साझा नहीं करने के लिए, कोई एपीआई नाम कुकी में जोड़ सकता है। लेकिन फिर भी कोई व्यक्ति आसानी से नए टोकन के अनुरोध पर CSRF सत्यापन कुकी को ताज़ा नहीं कर सकता है, क्योंकि उपयोगकर्ता एक ही साइट को कई विंडो में ब्राउज़ कर रहे हों, एक ही कुकी साझा कर रहे हों (जो कि ताज़ा होने पर, सभी विंडो में अपडेट हो जाए, जिसके बाद अन्य विंडो में जावास्क्रिप्ट टोकन अब उस एकल कुकी से मेल नहीं खाता)।
OAuth का उपयोग करने वालों के लिए, OAuth और क्लाइंट-साइड विजेट भी देखें , जिनसे मुझे जावास्क्रिप्ट विचार मिला। एपीआई के सर्वर साइड उपयोग के लिए, जिसमें हम डोमेन को सीमित करने के लिए जावास्क्रिप्ट कोड पर भरोसा नहीं कर सकते, हम सार्वजनिक एपीआई कुंजी के बजाय गुप्त कुंजी का उपयोग कर रहे हैं।