Java.util.Random और java.security.SecureRandom के बीच अंतर


202

मेरी टीम को कुछ सर्वर साइड कोड (जावा में) सौंपे गए जो यादृच्छिक टोकन उत्पन्न करते हैं और मेरे पास उसी के बारे में एक प्रश्न है -

इन टोकन का उद्देश्य काफी संवेदनशील है - सत्र आईडी, पासवर्ड रीसेट लिंक आदि के लिए उपयोग किया जाता है। टोकन एक "लंबा" है, इसलिए यह 64 बिट लंबा है।

कोड वर्तमान में java.util.Randomइन टोकन को उत्पन्न करने के लिए वर्ग का उपयोग करता है । प्रलेखन के लिए java.util.Randomस्पष्ट रूप से निम्नलिखित:

Java.util.Random के उदाहरण क्रिप्टोग्राफिक रूप से सुरक्षित नहीं हैं। सुरक्षा-संवेदनशील अनुप्रयोगों द्वारा उपयोग के लिए एक क्रिप्टोग्राफिक रूप से सुरक्षित छद्म यादृच्छिक संख्या जनरेटर प्राप्त करने के लिए SecureRandom का उपयोग करने के बजाय विचार करें।

हालाँकि, वर्तमान में जिस तरह से कोड का उपयोग किया जा रहा है java.util.Randomवह यह है - यह java.security.SecureRandomक्लास को इंस्टेंटिअट्स करता है और फिर क्लास को SecureRandom.nextLong()इंस्टेंट करने के लिए उपयोग किए जाने वाले बीज को प्राप्त करने के लिए विधि का उपयोग करता है java.util.Random। तब यह java.util.Random.nextLong()टोकन उत्पन्न करने के लिए विधि का उपयोग करता है ।

तो अब मेरा सवाल है - क्या यह अभी भी असुरक्षित है कि java.util.Randomबीज का उपयोग किया जा रहा है java.security.SecureRandom? क्या मुझे कोड को संशोधित करने की आवश्यकता है ताकि यह java.security.SecureRandomटोकन उत्पन्न करने के लिए विशेष रूप से उपयोग करे ?

वर्तमान Randomमें स्टार्टअप पर कोड सीड एक बार


14
एक बार बोने के बाद, java.util.Random से आउटपुट संख्याओं का निर्धारक अनुक्रम होता है। आप ऐसा नहीं चाह सकते हैं।
पीटर 13tibraný

1
क्या कोड Randomएक बार स्टार्टअप पर बीज कर देता है , या क्या यह हर टोकन के लिए एक नया बीज देता है? उम्मीद है, यह एक बेवकूफ सवाल है, लेकिन मुझे लगा कि मैं जाँच करूँगा।
टॉम एंडरसन

8
रैंडम में केवल 48-बिट आंतरिक स्थिति होती है और अगले ^ () के 2 ^ 48 कॉल के बाद दोहराएगा, जिसका अर्थ है कि यह सभी संभव longया doubleमूल्यों का उत्पादन नहीं करेगा ।
पीटर लॉरी

3
एक और गंभीर समस्या है। 64 बिट्स का मतलब है 1.84 * 10 ^ 19 संभावित संयोजन जो एक परिष्कृत हमले का सामना करने के लिए बहुत कम है। ऐसी मशीनें हैं, जिन्होंने 60 घंटे में 90 * 10 ^ 9 कुंजी प्रति सेकंड के साथ 56 बिट डीईएस कोड (कारक 256 कम) को क्रैक किया। 128 बिट्स या दो लॉन्ग का उपयोग करें!
थोरस्टन एस।

जवाबों:


232

मानक ओरेकल जेडडीके 7 कार्यान्वयन का उपयोग करता है कि यादृच्छिक मूल्यों का उत्पादन करने के लिए एक रैखिक बधाई जेनरेटर कहा जाता है java.util.Random

से लिया java.util.Randomस्रोत कोड (JDK 7u2), विधि पर एक टिप्पणी से protected int next(int bits)है, जो एक है कि यादृच्छिक मान उत्पन्न करता है:

यह एक रेखीय अभिनंदनशील छद्म आयामी संख्या जनरेटर है, जैसा कि डीएच लेहमर द्वारा परिभाषित किया गया है और द आर्ट ऑफ कंप्यूटर प्रोग्रामिंग, वॉल्यूम 3: सेमिनुमेरिकल एल्गोरिदम , खंड 3.2.1 में डोनाल्ड ई। नुथ द्वारा वर्णित किया गया है ।

रैखिक बधाई देने वालों की भविष्यवाणी

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

कैसे एक रैखिक बधाई जेनरेटर को तोड़ने के लिए

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

सुरक्षा "बेहतर" बीज के साथ नहीं सुधरती है। इससे कोई फर्क नहीं पड़ता कि आप किसी यादृच्छिक मूल्य के साथ बीज उत्पन्न करते हैं SecureRandomया यहां तक ​​कि कई बार मर कर भी मूल्य पैदा करते हैं।

एक हमलावर केवल आउटपुट मानों से बीज की गणना करेगा। इस मामले में 2 ^ 48 की तुलना में काफी कम समय लगता है java.util.Random। अविश्वासियों ने इस प्रयोग को आजमाया , जहां यह दिखाया गया है कि आप भविष्य के Randomआउटपुट का अनुमान केवल दो (!) के आउटपुट मानों के आधार पर लगा सकते हैं। आधुनिक कंप्यूटर पर अभी आपके यादृच्छिक संख्याओं के उत्पादन की भविष्यवाणी करने में एक सेकंड का भी समय नहीं लगता है।

निष्कर्ष

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


4
बहुत मददगार हो सकता है, आप यह भी बता सकते हैं कि सिक्योर रैंडम कैसे काम करता है (ठीक उसी तरह जैसे आप कैसे रैंडम काम करते हैं) ..
gresdiplitude

4
वह सुरक्षित के उद्देश्य को पराजित करता है
अज़ुल्फ्लेम

मुझे पता है, उस पाठ को कठिन तरीके से सीखा। लेकिन एक कठिन साइबर और हार्ड-टू-सोर्स स्रोत अच्छी तरह से काम करता है। नॉच उस पर कुछ सीख सकता है (उसने अपने उपयोगकर्ता के पासवर्ड को एक .lastlogin फ़ाइल में एन्कोड किया, कुंजी के रूप में "
पासवर्डफाइल

1
यहाँ असली सवाल: अगर जावा एक समान एपीआई के साथ एक अधिक सुरक्षित चुभन पैदा कर सकता है, तो उन्होंने सिर्फ टूटी हुई जगह को क्यों नहीं बदला?
जोएल Coehoorn

11
@JoelCoehoorn ऐसा नहीं है कि Randomटूटा हुआ है - इसका उपयोग विभिन्न परिदृश्यों में किया जाना चाहिए। बेशक, आप हमेशा सिक्योर रैंडम का उपयोग कर सकते हैं। लेकिन सामान्य तौर पर, SecureRandomशुद्ध की तुलना में काफी धीमी है Random। और ऐसे मामले हैं जहां आप केवल अच्छे सांख्यिकीय गुणों और उत्कृष्ट प्रदर्शन में रुचि रखते हैं, लेकिन आप वास्तव में सुरक्षा के बारे में परवाह नहीं करते हैं: मोंटे-कार्लो सिमुलेशन एक अच्छा उदाहरण है। मैंने एक समान उत्तर में इस बारे में टिप्पणी की , शायद आपको यह उपयोगी लगे।
नक्काशी

72

एक रैंडम में केवल 48 बिट्स होते हैं जहां सिक्योर रैंडम 128 बिट तक हो सकता है। इसलिए धर्मनिरपेक्ष में दोहराए जाने की संभावना बहुत कम है।

रैंडsystem clock बीज के रूप में / या बीज उत्पन्न करने के लिए उपयोग करता है। इसलिए उन्हें आसानी से पुन: पेश किया जा सकता है यदि हमलावर उस समय को जानता है जिस पर बीज उत्पन्न हुआ था। लेकिन SecureRandom लेता है Random Dataअपने से os(- - सबसे ओएस इकट्ठा इन आंकड़ों उन्हें फाइलों में स्टोर वे कीस्ट्रोक्स आदि के बीच अंतराल हो सकता है /dev/random and /dev/urandom in case of linux/solarisकि बीज के रूप में और का उपयोग करता है)।
इसलिए यदि छोटा टोकन आकार ठीक है (रैंडम के मामले में), तो आप बिना किसी बदलाव के अपने कोड का उपयोग जारी रख सकते हैं, क्योंकि आप बीज उत्पन्न करने के लिए SecureRandom का उपयोग कर रहे हैं। लेकिन अगर आप बड़े टोकन चाहते हैं (जो विषय के अधीन नहीं हो सकता है brute force attacks) सिक्योर रैंडम के साथ जाएं -
यादृच्छिक के मामले में केवल 2^48प्रयासों की आवश्यकता होती है, आज उन्नत सीपीयू के साथ व्यावहारिक समय में इसे तोड़ना संभव है। लेकिन धर्मनिरपेक्षता के लिए 2^128प्रयासों की आवश्यकता होगी, जिसमें आज की उन्नत मशीनों के साथ भी तोड़ने में वर्षों लगेंगे।

देखें इस अधिक जानकारी के लिए लिंक।
EDIT
@emboss द्वारा दिए गए लिंक को पढ़ने के बाद, यह स्पष्ट है कि बीज, हालांकि यह शायद यादृच्छिक है, का उपयोग java.util.Random के साथ नहीं किया जाना चाहिए। आउटपुट को देखकर बीज की गणना करना बहुत आसान है।

सिक्योर रैंडम के लिए जाएं - नेटिव PRNG का उपयोग करें (जैसा कि ऊपर दिए गए लिंक में दिया गया है) क्योंकि यह /dev/randomप्रत्येक कॉल के लिए फ़ाइल से यादृच्छिक मान लेता हैnextBytes()। इस तरह से एक हमलावर उत्पादन को देख नहीं कर सकेंगे कुछ भी बाहर बनाने के लिए जब तक वह की सामग्री को नियंत्रित कर रहा है /dev/randomफ़ाइल (जो बहुत संभावना नहीं है) SHA1 PRNG एल्गोरिथ्म गणना बीज केवल एक बार और अपने वीएम अगर एक ही का उपयोग कर महीनों के लिए चल रहा है बीज, यह एक हमलावर द्वारा क्रैक किया जा सकता है जो आउटपुट को देख रहा है। नोट - यदि आप तेजी से कॉल कर रहे हैं तो आपके ओएस में यादृच्छिक बाइट्स (एन्ट्रॉपी) लिखने में सक्षम है , तो आप NATIVE PRNG का उपयोग करते समय परेशानी में पड़ सकते हैं । उस स्थिति में सिक्योरग्रैंडम के SHA1 PRNG उदाहरण और हर कुछ मिनट (या कुछ अंतराल) का उपयोग करें, इस उदाहरण को मान से अलग करें


nextBytes()/dev/randomnextBytes()सुरक्षित के एक नटखट PRNG उदाहरण। इन दो समानताओं को चलाने से यह सुनिश्चित होगा कि आप नियमित यादृच्छिक मूल्यों के साथ नियमित रूप से बीजारोपण कर रहे हैं, जबकि ऑपरेटिंग सिस्टम द्वारा प्राप्त एन्ट्रापी को भी समाप्त नहीं करेंगे।


यह 2 की तुलना में बहुत कम है ^ 48 की भविष्यवाणी करने के लिए Random, ओपी का उपयोग नहीं किया जाना चाहिए Random
नक्काशी

@ अम्बॉस: मैं ब्रूटफोर्स के बारे में बात कर रहा हूं।
अश्विन

1
लिनक्स के साथ ध्यान रखें: यह एन्ट्रापी थकावट (हार्डवेयर के साथ वीएम में अधिक) तक पहुंच सकता है! देखो /proc/sys/kernel/random/entropy_availऔर कुछ थ्रेड डंप के साथ जांचें कि पढ़ने पर बहुत लंबा इंतजार नहीं है/dev/random
यवेस मार्टिन

2
ध्यान दें कि Oracle JRE (कम से कम 1.7) डिफ़ॉल्ट रूप से / dev / urandom के साथ काम करता है और न कि dev / यादृच्छिक तो आपके उत्तर का प्रत्यय अब सही नहीं है। सत्यापित करने के लिए $ JAVA_HOME / lib / सुरक्षा / java.security सत्यापित करने के लिए securerandom.source प्रॉपर्टी
Boaz

1
हमारी java.security फ़ाइल में securerandom.source = फ़ाइल थी: / dev / urandom फाइल के बजाय: /// dev / urandom (फाइल प्रोटोकॉल के लिए कोलन के बाद दो स्लैश, फिर फाइल सिस्टम के रूट के लिए एक और स्लैश), जिससे यह वापस गिर जाए। / देव / यादृच्छिक के लिए, जो एंट्रॉपी पूल थकावट के साथ समस्याओं का कारण बना। इसे संपादित नहीं किया जा सका, इसलिए ऐप स्टार्टअप पर एक सिस्टम गुण java.security.egd को दाईं ओर सेट करना पड़ा।
मैक्सपूल

11

यदि आप java.util.Random.nextLong()एक ही बीज के साथ दो बार चलते हैं , तो यह एक ही संख्या का उत्पादन करेगा। सुरक्षा कारणों से आप इसके साथ रहना चाहते हैं java.security.SecureRandomक्योंकि यह बहुत कम अनुमानित है।

2 कक्षाएं समान हैं, मुझे लगता है कि आपको केवल एक रीफैक्टरिंग टूल के साथ बदलना Randomहोगा SecureRandomऔर आपके अधिकांश मौजूदा कोड काम करेंगे।


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

1
अलग-अलग सिक्योर रैंडम कार्यान्वयन हैं, कुछ PRNG हैं, कुछ नहीं हैं। दूसरी ओर, java.util.Random हमेशा PRNG (जैसा कि इसके Javadoc में परिभाषित किया गया है) है।
पीटर 15tibraný

3

यदि आपका मौजूदा कोड बदलना एक किफायती काम है, तो मेरा सुझाव है कि आप सिक्योरग्रैंड क्लास का उपयोग करें जैसा कि जावदोक में सुझाया गया है।

यहां तक ​​कि अगर आपको लगता है कि रैंडम क्लास कार्यान्वयन आंतरिक रूप से सिक्योर रैंडम क्लास का उपयोग करता है। आपको इसे इस तरह नहीं लेना चाहिए:

  1. अन्य VM कार्यान्वयन समान कार्य करते हैं।
  2. JDK के भविष्य के संस्करणों में रैंडम वर्ग का कार्यान्वयन अभी भी SecureRandom वर्ग का उपयोग करता है

तो यह प्रलेखन सुझाव का पालन करने और SecureRandom के साथ सीधे जाने के लिए एक बेहतर विकल्प है।


मुझे विश्वास नहीं है कि मूल प्रश्न में कहा गया है कि java.util.Randomकार्यान्वयन SecureRandomआंतरिक रूप से उपयोग किया जाता है , उन्होंने कहा कि उनका कोडSecureRandom बीज का उपयोग करता है Random। फिर भी, मैं अब तक दोनों उत्तरों से सहमत हूं; SecureRandomस्पष्ट रूप से निर्धारक समाधान से बचने के लिए इसका उपयोग करना सबसे अच्छा है ।
पलपीम

2

वर्तमान संदर्भ कार्यान्वयन java.util.Random.nextLong()उस विधि को दो कॉल करता है next(int)जो सीधे वर्तमान बीज के 32 बिट को उजागर करता है:

protected int next(int bits) {
    long nextseed;
    // calculate next seed: ...
    // and store it in the private "seed" field.
    return (int)(nextseed >>> (48 - bits));
}

public long nextLong() {
    // it's okay that the bottom word remains signed.
    return ((long)(next(32)) << 32) + next(32);
}

परिणाम के ऊपरी 32 बिट nextLong()उस समय बीज के बिट होते हैं। चूँकि बीज की चौड़ाई 48 बिट (जावदोक कहती है), यह शेष 16 बिट (जो केवल 65.536 की कोशिश करता है) पर पुनरावृत्ति करने के लिए * पर्याप्त है जो कि दूसरे 32 बिट का उत्पादन करने वाले बीज को निर्धारित करता है।

एक बार बीज ज्ञात हो जाने पर, निम्नलिखित सभी टोकन आसानी से गणना की जा सकती है।

nextLong()सीधे उत्पादन के उपयोग से , आंशिक रूप से PNG के रहस्य को एक हद तक पूरा कर दिया जा सकता है, जिससे संपूर्ण रहस्य की गणना बहुत कम गति से की जा सकती है। खतरनाक!

* दूसरा 32 बिट नकारात्मक होने पर कुछ प्रयास करने की आवश्यकता होती है, लेकिन कोई भी इसका पता लगा सकता है।


सही बात। जल्दी से java.util.random को jazzy.id.au/default/2010/09/20/… पर कैसे देखें !
23

2

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

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

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

अन्य शब्दों के साथ: आपको सभी को बदलना होगा।


0

मैं बहुत मूल शब्दों का उपयोग करने की कोशिश करूंगा ताकि आप रैंडम और सिक्योर रैंडम के बीच के अंतर और सिक्योर रैंडम क्लास के महत्व को आसानी से समझ सकें।

कभी आश्चर्य है कि ओटीपी (वन टाइम पासवर्ड) कैसे उत्पन्न होता है? OTP उत्पन्न करने के लिए हम रैंडम और सिक्योर रैंडम क्लास का भी उपयोग करते हैं। अब अपने ओटीपी को मजबूत बनाने के लिए, सिक्योर रैंडम बेहतर है क्योंकि ओटीपी को क्रैक करने के लिए 2 ^ 128 का प्रयास किया गया है, जो वर्तमान मशीन द्वारा लगभग असंभव है लेकिन यदि रैंडम क्लास का उपयोग किया जाता है तो आपके ओटीपी को किसी ऐसे व्यक्ति द्वारा क्रैक किया जा सकता है जो आपके डेटा को नुकसान पहुंचा सकता है क्योंकि इसे लिया गया था बस 2 ^ 48 दरार करने के लिए प्रयास करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.