"कभी-कभी ऑफ़लाइन" वेब ऐप में उपयोग के लिए अद्वितीय और सुरक्षित पहचानकर्ता बनाने के लिए रणनीति


47

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

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

नीचे मेरा प्रस्तावित समाधान है।

कुछ आवश्यकताएँ

  1. आईडी विश्व स्तर पर अद्वितीय होनी चाहिए (या सिस्टम के भीतर कम से कम अद्वितीय)
  2. ग्राहक पर उत्पन्न (यानी ब्राउज़र में जावास्क्रिप्ट के माध्यम से)
  3. सुरक्षित (ऊपर उल्लिखित और अन्यथा)
  4. डेटा को कई उपयोगकर्ताओं द्वारा देखा / संपादित किया जा सकता है, जिसमें वे उपयोगकर्ता भी शामिल हैं जिन्होंने इसे लेखक नहीं किया
  5. बैकएंड db (जैसे MongoDB या CouchDB) के लिए महत्वपूर्ण प्रदर्शन समस्याएँ पैदा नहीं करता है

प्रस्तावित समाधान

जब उपयोगकर्ता एक खाता बनाते हैं, तो उन्हें एक यूआईडी दिया जाएगा जो सर्वर द्वारा उत्पन्न किया गया था और सिस्टम के भीतर अद्वितीय होने के लिए जाना जाता था। यह आईडी उपयोगकर्ताओं के प्रमाणीकरण टोकन के समान नहीं होनी चाहिए। चलिए इस आईडी को यूजर्स "id token" कहते हैं।

जब कोई उपयोगकर्ता एक नया रिकॉर्ड बनाता है, तो वे जावास्क्रिप्ट में एक नया यूआईडी बनाते हैं (जब उपलब्ध विंडो। क्रिप्टो का उपयोग करके उत्पन्न होता है। यहां उदाहरण देखें )। इस आईडी को "आईडी टोकन" के साथ मिलाया जाता है जब उपयोगकर्ता ने अपना खाता बनाया था। यह नई समग्र आईडी (सर्वर साइड आईडी टोकन + क्लाइंट साइड यूआईडी) अब रिकॉर्ड के लिए अद्वितीय पहचानकर्ता है। जब उपयोगकर्ता ऑनलाइन होता है और बैकएंड सर्वर पर इस नए रिकॉर्ड को जमा करता है, तो सर्वर होगा:

  1. इसे "इन्सर्ट" एक्शन के रूप में पहचानें (अर्थात अपडेट या डिलीट नहीं)
  2. संयुक्त कुंजी के दोनों हिस्सों को मान्य uuids मान्य हैं
  3. सत्यापित करें कि समग्र आईडी का प्रदान किया गया "आईडी टोकन" वर्तमान उपयोगकर्ता के लिए सही है (अर्थात यह उपयोगकर्ता द्वारा असाइन किए गए सर्वर से आईडी टोकन से मेल खाता है जब उन्होंने अपना खाता बनाया था)
  4. यदि सब कुछ डाटाबेस में copasetic, डेटा डालने है (सावधान किया जा रहा है एक डालने और नहीं एक "Upsert" ऐसा करने के लिए इतना है कि यदि आईडी करता है पहले से मौजूद है यह गलती से एक मौजूदा रिकॉर्ड को अपडेट नहीं करता है)

क्वेरी, अपडेट और डिलीट को किसी विशेष तर्क की आवश्यकता नहीं होगी। वे बस पारंपरिक अनुप्रयोगों के रूप में रिकॉर्ड के लिए आईडी का उपयोग करेंगे।

इस दृष्टिकोण के क्या फायदे हैं?

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

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

  3. चूंकि एक यूजर आईडी टोकन उनके खाते से जुड़ा हुआ है, इसलिए आईडी केवल एक उपयोगकर्ता सैंडबॉक्स में उन ग्राहकों द्वारा उत्पन्न की जा सकती है जो प्रमाणित हैं (यानी जहां उपयोगकर्ता सफलतापूर्वक लॉग इन किया गया है)। यह एक उपयोगकर्ता के लिए खराब आईडी बनाने से दुर्भावनापूर्ण क्लाइंट रखने का इरादा है। बेशक अगर किसी उपयोगकर्ता के टोकन को दुर्भावनापूर्ण क्लाइंट द्वारा चोरी किया गया था, तो वे खराब काम कर सकते हैं। लेकिन, एक बार एक टोकन के चोरी हो जाने पर खाता किसी भी तरह से समझौता कर लिया जाता है। ऐसा होने की स्थिति में, जो नुकसान हुआ है वह समझौता किए गए खाते (संपूर्ण प्रणाली नहीं) तक सीमित होगा।

चिंताओं

इस दृष्टिकोण के साथ मेरी कुछ चिंताएं हैं

  1. क्या यह बड़े पैमाने पर आवेदन के लिए पर्याप्त रूप से अद्वितीय आईडी उत्पन्न करेगा? क्या यह सोचने का कोई कारण है कि इसके परिणामस्वरूप आईडी टकराव होगा? क्या जावास्क्रिप्ट इस काम के लिए एक पर्याप्त यादृच्छिक यूआईडी उत्पन्न कर सकता है? ऐसा लगता है कि window.crypto काफी व्यापक रूप से उपलब्ध है और इस परियोजना के लिए पहले से ही काफी आधुनिक ब्राउज़रों की आवश्यकता है। ( इस सवाल का अब एक अलग SO प्रश्न है )

  2. क्या कोई खामी है जो मुझे याद आ रही है जो किसी दुर्भावनापूर्ण उपयोगकर्ता को सिस्टम से समझौता करने की अनुमति दे सकती है?

  3. क्या 2 uuids से बनी कंपोजिट कुंजी की क्वेरी करते समय DB प्रदर्शन के बारे में चिंता करने का कारण है। सर्वश्रेष्ठ प्रदर्शन के लिए इस आईडी को कैसे संग्रहीत किया जाना चाहिए? दो अलग-अलग फ़ील्ड या एक ऑब्जेक्ट फ़ील्ड? क्या मोंगो बनाम काउच के लिए एक अलग "सर्वश्रेष्ठ" दृष्टिकोण होगा? मुझे पता है कि आवेषण करते समय एक गैर-अनुक्रमिक प्राथमिक कुंजी होने से उल्लेखनीय प्रदर्शन मुद्दे हो सकते हैं। क्या प्राथमिक कुंजी के लिए एक ऑटो उत्पन्न मूल्य रखना और इस आईडी को एक अलग क्षेत्र के रूप में संग्रहित करना बेहतर होगा? ( इस सवाल का अब एक अलग SO प्रश्न है )

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

  5. इस घटना में कि उपयोगकर्ता के लिए एक आईडी टकराव है, ठीक होने का एक सरल तरीका नहीं है। मुझे लगता है कि ग्राहक एक नई आईडी तैयार कर सकता है, लेकिन यह एक किनारे मामले के लिए बहुत काम की तरह लगता है जो वास्तव में कभी नहीं होना चाहिए। मैं इस अभागे को छोड़ने का इरादा कर रहा हूं।

  6. केवल प्रमाणित उपयोगकर्ता ही डेटा देख और / या संपादित कर सकते हैं। यह मेरे सिस्टम के लिए एक स्वीकार्य सीमा है।

निष्कर्ष

एक उचित योजना से ऊपर है? मुझे लगता है कि इसमें से कुछ को निर्णय में आवेदन की पूरी समझ के आधार पर एक निर्णय कॉल के लिए आता है।


मुझे लगता है कि यह सवाल आपको stackoverflow.com/questions/105034/… को पढ़ सकता है, यह भी मुझे GUID की तरह पढ़ा है, लेकिन वे जावास्क्रिप्ट में मूल नहीं लगते
Rémi

2
यह मुझे बताता है कि UUIDs पहले से ही 5 सूचीबद्ध आवश्यकताओं को पूरा करते हैं। वे अपर्याप्त क्यों हैं?
गाबे

@Gabe नीचे झूठे रेयान पोस्ट पर मेरी टिप्पणियाँ देखें
herbrandson

इस सवाल की मेटा चर्चा: meta.stackoverflow.com/questions/251215/…
gnat

"दुर्भावनापूर्ण / रूज क्लाइंट" - दुष्ट।
डेविड कॉनरैड

जवाबों:


4

आपका दृष्टिकोण काम करेगा। बहुत सारे दस्तावेज़ प्रबंधन सिस्टम इस प्रकार के दृष्टिकोण का उपयोग करते हैं।

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

आपके पास एक और विकल्प है कि आप प्रत्येक आइटम के लिए सिर्फ एक अस्थायी uuid उत्पन्न करें। फिर जब आप कनेक्ट करते हैं और उन्हें सर्वर पर पोस्ट करते हैं, तो सर्वर प्रत्येक आइटम के लिए यूआईडी (गारंटीकृत) करता है और आपको देता है। फिर आप अपनी स्थानीय प्रति अपडेट करें।


2
मैंने 2 के हैश का उपयोग आईडी के रूप में किया था। हालाँकि, यह मुझे दिखाई नहीं दिया कि सभी ब्राउज़रों में एक sha256 उत्पन्न करने के लिए एक उपयुक्त तरीका है जिसे मुझे समर्थन करने की आवश्यकता है :(
herbrandson

12

आपको दो चिंताओं को अलग करने की आवश्यकता है:

  1. आईडी जनरेशन: क्लाइंट को वितरित सिस्टम में एक विशिष्ट पहचानकर्ता बनाने में सक्षम होना चाहिए
  2. सुरक्षा चिंता: ग्राहक के पास एक वैध उपयोगकर्ता प्रमाणीकरण टोकन होना चाहिए और प्रमाणीकरण टोकन ऑब्जेक्ट के निर्माण / संशोधित होने के लिए मान्य है

दुर्भाग्य से इन दोनों का समाधान अलग-अलग है; लेकिन सौभाग्य से वे असंगत नहीं हैं।

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

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


यह वास्तव में एक अच्छा बिंदु है। शायद यह सब जरूरी है और मैं इसे खत्म कर रहा हूं। हालाँकि, मुझे इस दृष्टिकोण के बारे में कुछ चिंताएँ हैं। सबसे बड़ी बात यह है कि जावास्क्रिप्ट से उत्पन्न uuids उतने बेतरतीब नहीं लगते जितना कि कोई उम्मीद कर सकता है (डिटेन के लिए stackoverflow.com/a/2117523/13181 पर टिप्पणियां देखें )। ऐसा लगता है कि window.crypto को इस समस्या को हल करना चाहिए, लेकिन यह सभी ब्राउज़र संस्करणों में उपलब्ध नहीं लगता है जिन्हें मुझे समर्थन करने की आवश्यकता है।
हर्बर्न्सन

जारी रखा ... मुझे क्लाइंट में कोड जोड़ने का आपका सुझाव पसंद है जो एक टकराव के मामले में एक नया यूआईडी पुनर्जीवित करेगा। हालाँकि, यह मुझे लगता है कि इस चिंता का फिर से परिचय है जो मैंने अपने पोस्ट में "इस दृष्टिकोण के फायदे क्या हैं" बिंदु 1 के तहत किया था। मुझे लगता है कि अगर मैं उस रास्ते पर चला गया, तो मैं ग्राहक की तरफ अस्थायी अस्थायी आईडी बनाने से बेहतर होगा और फिर सर्वर से "फाइनल आईडी" के साथ एक बार कनेक्ट होने के बाद उन्हें अपडेट करूंगा
herbrandson

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

@herbrandson: ऐसा कोई सुरक्षा मुद्दा नहीं है जिसके बारे में मैं सोच सकता हूँ कि जब तक उपयोगकर्ता हमेशा यह जाँचने की अनुमति दे कि उपयोगकर्ता के पास अपनी विशिष्ट आईडी बनाने की अनुमति है। आईडी सिर्फ एक चीज है जिसका उपयोग वस्तुओं की पहचान करने के लिए किया जा सकता है, यह वास्तव में मायने नहीं रखता है कि इसका मूल्य क्या है। एकमात्र संभावित नुकसान यह है कि उपयोगकर्ता अपने स्वयं के उपयोग के लिए कई प्रकार की आईडी आरक्षित कर सकता है, लेकिन यह वास्तव में सिस्टम को पूरी तरह से कोई समस्या नहीं देता है क्योंकि अन्य उपयोगकर्ता बस उन अवसरों पर अकेले आने की संभावना नहीं रखते हैं।
रेयान

आपकी प्रतिक्रिया के लिए धन्यवाद। यह वास्तव में मुझे अपनी सोच स्पष्ट करने के लिए मजबूर कर रहा है! वहाँ एक कारण है कि मैं आपके दृष्टिकोण से सावधान था, और मैं इसे रास्ते में भूल गया था :)। मेरा डर कई ब्राउज़रों में गरीब RNG से जुड़ा हुआ है। Uuid पीढ़ी के लिए, व्यक्ति क्रिप्टोग्राफिक रूप से मजबूत आरएनजी को पसंद करेगा। कई नए ब्राउज़रों में window.crypto के माध्यम से यह है, लेकिन पुराने ब्राउज़र नहीं हैं। इसके कारण, एक दुर्भावनापूर्ण उपयोगकर्ता के लिए यह संभव है कि वह किसी अन्य उपयोगकर्ता RNG के बीज का पता लगा सके और इस तरह अगले uuid को जान सकेगा जो उत्पन्न होगा। यह वह हिस्सा है जिसे लगता है कि इस पर हमला किया जा सकता है।
जड़ी बूटी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.