पासवर्ड के लिए स्ट्रिंग [] को क्यों पसंद किया जाता है?


3421

स्विंग में, पासवर्ड फ़ील्ड में सामान्य (रिटर्न ) विधि के बजाय एक getPassword()(रिटर्न char[]) विधि होती है। इसी तरह, मैं पासवर्डों को संभालने के लिए उपयोग न करने के सुझाव के साथ आया हूं ।getText()StringString

Stringजब पासवर्ड की बात आती है तो सुरक्षा के लिए खतरा क्यों है ? यह उपयोग करने में असुविधाजनक लगता है char[]

जवाबों:


4287

तार अपरिवर्तनीय हैं । इसका मतलब है कि एक बार जब आप बना लेते हैं String, अगर एक और प्रक्रिया मेमोरी को डंप कर सकती है, तो कोई रास्ता नहीं है ( प्रतिबिंब से अलग ) आप कचरा संग्रह में किक से पहले डेटा से छुटकारा पा सकते हैं ।

एक सरणी के साथ, आप इसके साथ काम करने के बाद डेटा को स्पष्ट रूप से मिटा सकते हैं। आप अपनी पसंद की किसी भी चीज़ के साथ सरणी को ओवरराइट कर सकते हैं, और पासवर्ड सिस्टम में कहीं भी मौजूद नहीं होगा, कचरा संग्रह से पहले भी।

तो हाँ, यह है एक सुरक्षा चिंता का विषय है - लेकिन फिर भी का उपयोग कर char[]केवल एक हमलावर के लिए अवसर की खिड़की कम कर देता है, और यह केवल हमले की इस विशेष प्रकार के लिए है।

जैसा कि टिप्पणियों में उल्लेख किया गया है, यह संभव है कि कचरा कलेक्टर द्वारा स्थानांतरित किए जा रहे सरणियों को स्मृति में डेटा की आवारा प्रतियां छोड़ देंगी। मेरा मानना ​​है कि यह कार्यान्वयन-विशिष्ट है - कचरा कलेक्टर इस तरह की चीज़ों से बचने के लिए सभी मेमोरी को साफ कर सकता है। अगर ऐसा होता भी है, तब भी वह समय होता है, char[]जिसमें हमले की खिड़की के रूप में वास्तविक अक्षर होते हैं।


3
यदि किसी प्रक्रिया में आपके एप्लिकेशन की मेमोरी तक पहुंच है, तो वह पहले से ही सुरक्षा उल्लंघन है, है ना?
यति

5
@ येटी: हां, लेकिन ऐसा नहीं है कि यह ब्लैक एंड व्हाइट है। यदि वे केवल मेमोरी का स्नैपशॉट प्राप्त कर सकते हैं तो आप कम करना चाहते हैं कि स्नैपशॉट कितना नुकसान कर सकता है या उस विंडो को कम कर सकता है जिसके दौरान वास्तव में गंभीर स्नैपशॉट लिया जा सकता है।
जॉन स्कीट

11
एक सामान्य हमला विधि एक ऐसी प्रक्रिया को चलाने के लिए है जो बहुत सारी मेमोरी आवंटित करती है और फिर इसे बाएं-ओवर, उपयोगी डेटा जैसे पासवर्ड के लिए स्कैन करती है। प्रक्रिया को किसी अन्य प्रक्रिया की मेमोरी स्पेस में किसी जादुई पहुंच की आवश्यकता नहीं है; यह सिर्फ संवेदनशील डेटा को साफ़ करने के बिना मरने वाली अन्य प्रक्रियाओं पर निर्भर करता है और ओएस एक नई प्रक्रिया को उपलब्ध कराने से पहले मेमोरी (या पेज बफ़र्स) को भी साफ़ नहीं करता है। char[]स्थानों में संग्रहीत पासवर्ड को साफ़ करना हमले की उस पंक्ति को काट देता है, जिसका उपयोग करते समय कुछ संभव नहीं है String
टेड होप

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

1221

जबकि अन्य सुझाव यहां मान्य हैं, एक और अच्छा कारण है। सादे के साथ Stringआपके पास लॉग , मॉनिटर या किसी अन्य असुरक्षित जगह पर गलती से पासवर्ड प्रिंट करने की अधिक संभावना है। char[]कम कमजोर है।

इस पर विचार करो:

public static void main(String[] args) {
    Object pw = "Password";
    System.out.println("String: " + pw);

    pw = "Password".toCharArray();
    System.out.println("Array: " + pw);
}

प्रिंटों:

String: Password
Array: [C@5829428e

40
@voo, लेकिन मुझे संदेह है कि आप सीधे लेखन के माध्यम से स्ट्रीम और कॉनटेनटेशन में प्रवेश करेंगे। लॉगिंग फ्रेमवर्क चार को अच्छे आउटपुट में बदल देगा
सर्वश्रेष्ठ

41
@ Thr4wn का डिफ़ॉल्ट कार्यान्वयन toStringहै classname@hashcode[Cप्रतिनिधित्व करता है char[], बाकी हेक्साडेसिमल हैश कोड है।
कोनराड गरुस २०'१२

15
दिलचस्प विचार। मैं यह बताना चाहता हूं कि यह स्काला को हस्तांतरित नहीं करता है, जिसका अर्थ है ऐरे के लिए स्टर्लिंग।
मौहिज़

37
मैं इसके लिए एक Passwordक्लास टाइप लिखूंगा । यह कम अस्पष्ट है, और गलती से कहीं और गुजरना मुश्किल है।
19

8
कोई यह मान लेगा कि चार सरणी वस्तु के रूप में डाली जा रही है? मुझे यकीन नहीं है कि मुझे यह जवाब क्यों पसंद है। मान लीजिए कि आपने ऐसा किया: System.out.println ("पासवर्ड" .toCharArray ());
GC_

680

एक आधिकारिक दस्तावेज़ को उद्धृत करने के लिए, जावा क्रिप्टोग्राफी आर्किटेक्चर गाइड यह char[]बनाम Stringपासवर्ड (पासवर्ड-आधारित एन्क्रिप्शन के बारे में कहता है , लेकिन यह आम तौर पर पासवर्ड के बारे में अधिक है):

यह एक प्रकार की वस्तु में पासवर्ड को इकट्ठा करने और संग्रहीत करने के लिए तर्कसंगत प्रतीत होगा java.lang.String। हालाँकि, यहाँ पर यह चेतावनी दी गई है: Objectप्रकार Stringअपरिवर्तनीय हैं, अर्थात, ऐसी कोई विधियाँ निर्धारित नहीं की गई हैं, जो आपको String उपयोग के बाद सामग्री को बदलने (अधिलेखित) या शून्य करने की अनुमति दें । यह सुविधा Stringऑब्जेक्ट को उपयोगकर्ता के पासवर्ड जैसी संवेदनशील संवेदनशील जानकारी संग्रहीत करने के लिए अनुपयुक्त बनाती है । आपको हमेशा charइसके बजाय सरणी में सुरक्षा संवेदनशील जानकारी एकत्र और संग्रहीत करनी चाहिए ।

जावा प्रोग्रामिंग लैंग्वेज के लिए सिक्योर कोडिंग गाइडलाइंस की गाइडलाइन 2-2, वर्जन 4.0 भी कुछ ऐसा ही कहती है (हालाँकि यह मूल रूप से लॉगिंग के संदर्भ में है):

दिशानिर्देश 2-2: अत्यधिक संवेदनशील जानकारी लॉग न करें

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

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


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

37
क्या आप कृपया एक संदर्भ का हवाला भी दे सकते हैं?
user961954

10
@bestass क्षमा करें, लेकिन Stringबहुत अच्छी तरह से समझा जाता है और यह जेवीएम में कैसे व्यवहार करता है ... पासवर्ड के साथ सुरक्षित तरीके से व्यवहार करने char[]के स्थान पर उपयोग करने के अच्छे कारण हैं String
स्नेकडोक

3
हालांकि एक बार फिर पासवर्ड ब्राउज़र से एक स्ट्रिंग के रूप में पास किया जाता है, 'स्ट्रिंग' के रूप में अनुरोध के लिए नहीं? तो इससे कोई फर्क नहीं पड़ता कि आप क्या करते हैं यह एक स्ट्रिंग है, जिस बिंदु पर इसे लागू किया जाना चाहिए और खारिज कर दिया जाना चाहिए, कभी स्मृति में संग्रहीत नहीं किया जाता है?
दाविसी

3
@Dawesi - At which point- यह एप्लिकेशन विशिष्ट है, लेकिन सामान्य नियम यह है कि जैसे ही आप किसी ऐसी चीज को पकड़ लें, जिसे पासवर्ड (सादा या अन्यथा) माना जाता है। उदाहरण के लिए, आप इसे HTTP अनुरोध के भाग के रूप में ब्राउज़र से प्राप्त करते हैं। आप वितरण को नियंत्रित नहीं कर सकते हैं, लेकिन आप अपने स्वयं के भंडारण को नियंत्रित कर सकते हैं, इसलिए जैसे ही आप इसे प्राप्त करते हैं, इसे एक चार में डाल दें [], इसके साथ आपको क्या करना है, फिर सभी को '0' पर सेट करें और gc दें इसे पुनः प्राप्त करें।
luis.espinal

354

चरित्र सरणियों ( char[]) को प्रत्येक वर्ण को शून्य और स्ट्रिंग्स में सेट करके उपयोग के बाद साफ़ किया जा सकता है। यदि कोई किसी तरह से मेमोरी इमेज देख सकता है, तो वे सादे टेक्स्ट में एक पासवर्ड देख सकते हैं यदि स्ट्रिंग्स का उपयोग किया जाता है, लेकिन यदि char[]उपयोग किया जाता है, तो 0 के साथ डेटा को शुद्ध करने के बाद, पासवर्ड सुरक्षित है।


13
डिफ़ॉल्ट रूप से सुरक्षित नहीं है। यदि हम एक वेब एप्लिकेशन के बारे में बात कर रहे हैं, तो अधिकांश वेब कंटेनर HttpServletRequestसादे वस्तु में पासवर्ड को पास करेंगे । यदि JVM संस्करण 1.6 या उससे कम है, तो यह permgen स्थान में होगा। यदि यह 1.7 में है, तो यह तब तक पठनीय रहेगा जब तक कि यह एकत्र नहीं हो जाता। (जब भी ऐसा हो।)
avgvstvs

4
@avgvstvs: स्ट्रिंग्स स्वचालित रूप से पर्मगेन स्पेस में नहीं ले जाते हैं, यह केवल इंटर्नड स्ट्रिंग्स पर लागू होता है। इसके अलावा, परमेजन स्थान भी कम दर पर कचरा संग्रहण के अधीन है। पर्मगेन स्पेस के साथ वास्तविक मुद्दा यह निश्चित आकार है, यही कारण है कि किसी को भी intern()मनमाने ढंग से तार पर कॉल नहीं करना चाहिए । लेकिन आप सही हैं कि Stringउदाहरण पहले स्थान पर (एकत्र किए जाने तक) मौजूद हैं और char[]बाद में उन्हें सरणियों में बदलना इसे परिवर्तित नहीं करता है।
होल्गर

3
@ होलियर देखें docs.oracle.com/javase/specs/jvms/se6/html/… "अन्यथा, क्लास स्ट्रिंग का एक नया उदाहरण CONSTANT_ring_info संरचना द्वारा दिए गए यूनिकोड वर्णों के अनुक्रम को मिलाकर बनाया गया है; यह वर्ग उदाहरण का परिणाम है स्ट्रिंग शाब्दिक व्युत्पत्ति। अंत में, नए स्ट्रिंग उदाहरण की आंतरिक विधि का उपयोग किया जाता है। " 1.6 में, JVM आपके लिए इंटर्न कॉल करेगा जब उसने समान दृश्यों का पता लगाया था।
एवग्स्टव्स

3
@ होल्गर, आप सही हैं मैंने निरंतर पूल और स्ट्रिंग पूल को जब्त कर लिया है, लेकिन यह भी गलत है कि परमिटेन स्पेस केवल नजरबंद तारों पर लागू होता है। 1.7 से पहले, दोनों स्थिर_पूल और स्ट्रिंग_पूल पेरेगेन स्पेस में रहते थे। इसका मतलब है कि स्ट्रिंग्स का एकमात्र वर्ग जो ढेर को आवंटित किया गया था, जैसा कि आपने कहा था, new String()या StringBuilder.toString() मैंने बहुत सारे स्ट्रिंग स्थिरांक के साथ अनुप्रयोगों का प्रबंधन किया, और परिणामस्वरूप हमारे पास बहुत सारे परमिट क्रिप थे। 1.7 तक।
अवीवस्तव्स

5
@avgvstvs: ठीक है, स्ट्रिंग स्थिरांक हैं, जेएलएस जनादेश के रूप में, हमेशा नजरबंद होते हैं, इसलिए यह कथन कि इंटर्न स्ट्रिंग्स पारगमेन स्पेस में समाप्त हो गया है, स्ट्रिंग स्थिरांक पर लागू होता है। अंतर केवल यह है कि स्ट्रिंग स्थिरांक को पहली बार पारगम्य स्थान में बनाया गया था, जबकि intern()एक मनमाने तार पर कॉल करने से पारगम्य स्थान में एक समतुल्य स्ट्रिंग का आवंटन हो सकता है। उत्तरार्द्ध GC'ed प्राप्त कर सकता है, अगर उस वस्तु को साझा करने वाली समान सामग्री का कोई शाब्दिक स्ट्रिंग नहीं था ...
होल्गर

220

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

अपडेट करें

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

  • आपका लक्ष्य सिस्टम बुरी तरह से कॉन्फ़िगर किया जा सकता है या आपको यह मान लेना होगा कि आपको कोर डंप के बारे में अवगत होना होगा (यदि सिस्टम किसी व्यवस्थापक द्वारा प्रबंधित नहीं किया गया है तो यह मान्य हो सकता है)।
  • जैसी चीजों का उपयोग कर - अपने सॉफ्टवेयर ज्यादा हमलावर हार्डवेयर तक एक्सेस प्राप्त करने डेटा लीक को रोकने के लिए पागल हो गया है TrueCrypt (बंद), VeraCrypt , या CipherShed

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


33
मैं "सिर्फ एक मामूली सुरक्षा सुधार" के साथ "पूरी तरह से बेकार" को बदल दूंगा। उदाहरण के लिए, यदि आप एक tmp निर्देशिका, एक बुरी तरह से कॉन्फ़िगर की गई मशीन और आपके अनुप्रयोग में कोई क्रैश के लिए पढ़ा हो, तो आप मेमोरी डंप तक पहुँच प्राप्त कर सकते हैं। उस स्थिति में आप एक keylogger स्थापित करने में सक्षम नहीं होंगे, लेकिन आप कोर डंप का विश्लेषण कर सकते हैं
जोकिम सॉर

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

9
मैं इस प्रतिक्रिया के दृष्टिकोण से सहमत हूं। मैं स्मृति में बिट्स की तुलना में एब्सट्रैक्शन के उच्च स्तर पर होने वाले परिणाम के अधिकांश सुरक्षा उल्लंघनों का प्रस्ताव करने के लिए उद्यम करूँगा। निश्चित रूप से, हाइपर-सुरक्षित रक्षा प्रणालियों में संभवतः परिदृश्य होते हैं जहां यह काफी चिंता का विषय हो सकता है लेकिन इस स्तर पर गंभीरता से सोचना 99% अनुप्रयोगों के लिए ओवरकिल है जहां .NET या Java का उपयोग किया जा रहा है (जैसा कि यह कचरा संग्रह से संबंधित है)।

10
सर्वर मेमोरी के हार्टबल प्रवेश के बाद, पासवर्ड का खुलासा करते हुए, मैं स्ट्रिंग को "सिर्फ एक मामूली सुरक्षा सुधार" के साथ बदल दूंगा "पासवर्ड के लिए स्ट्रिंग का उपयोग नहीं करने के लिए, लेकिन इसके बजाय एक चार [] का उपयोग करें।"
पीटर vdL

9
@PetervdL ने केवल बफ़र्स के एक विशिष्ट पुन: उपयोग किए गए संग्रह को पढ़ने की अनुमति दी है (दोनों सुरक्षा महत्वपूर्ण डेटा और नेटवर्क I / O के लिए उपयोग किया जाता है - बीच-बीच में बिना किसी कारण के क्लीयरेंस के लिए - प्रदर्शन कारणों से), आप इसे जावा स्ट्रिंग के साथ संयोजित नहीं कर सकते हैं क्योंकि वे डिज़ाइन के लिए पुन: प्रयोज्य नहीं हैं। । न ही आप स्ट्रिंग की सामग्री को प्राप्त करने के लिए जावा का उपयोग करके यादृच्छिक मेमोरी में पढ़ सकते हैं। भाषा और डिज़ाइन की समस्याएं, जो हृदय विदारक होती हैं, केवल जावा स्ट्रिंग्स के साथ संभव नहीं हैं।
जोसेफ

86

मुझे नहीं लगता कि यह एक वैध सुझाव है, लेकिन, मैं कम से कम इस कारण का अनुमान लगा सकता हूं।

मुझे लगता है कि प्रेरणा यह सुनिश्चित करना चाहती है कि आप स्मृति में पासवर्ड के सभी ट्रेस को तुरंत और निश्चित रूप से उपयोग किए जाने के बाद मिटा सकते हैं। एक साथ char[]आप एक खाली या यकीन है कि के लिए कुछ के साथ सरणी के प्रत्येक तत्व के ऊपर लिख सकता है। आप Stringउस तरह से आंतरिक मूल्य को संपादित नहीं कर सकते ।

लेकिन यह अकेले एक अच्छा जवाब नहीं है; क्यों नहीं बस सुनिश्चित करें कि एक संदर्भ के लिए char[]या Stringबच नहीं करता है? तब कोई सुरक्षा समस्या नहीं है। लेकिन बात यह है कि Stringवस्तुओं को intern()सिद्धांत रूप में एड किया जा सकता है और निरंतर पूल के अंदर जीवित रखा जा सकता है । मुझे लगता है कि char[]इस संभावना का उपयोग करने से मना किया जाता है।


4
मैं यह नहीं कहूंगा कि समस्या यह है कि आपके संदर्भ "बचेंगे" या नहीं होंगे। यह सिर्फ इतना है कि तार कुछ अतिरिक्त समय के लिए मेमोरी में अनमॉडिफाइड रहेंगे, जबकि char[]इसे संशोधित किया जा सकता है, और फिर यह अप्रासंगिक है कि यह एकत्र किया गया है या नहीं। और चूंकि स्ट्रिंग इंटर्निंग को गैर-शाब्दिक रूप से स्पष्ट रूप से किए जाने की आवश्यकता है, इसलिए यह बताने के समान है कि char[]एक स्थिर क्षेत्र द्वारा संदर्भित किया जा सकता है।
ग्रू

1
फॉर्म पोस्ट से स्ट्रिंग के रूप में मेमोरी में पासवर्ड नहीं है?
दाविसी

66

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

मैं PrivateKey की तरह सोच रहा हूँ वर्ग । एक परिदृश्य पर विचार करें जहां आप PKCS # 12 फ़ाइल से एक निजी RSA कुंजी लोड करेंगे, इसका उपयोग कुछ ऑपरेशन करने के लिए। अब इस मामले में, अकेले पासवर्ड को सूँघने से आपको ज्यादा मदद नहीं मिलेगी, जब तक कि की फाइल की भौतिक पहुंच ठीक से प्रतिबंधित नहीं हो जाती। एक हमलावर के रूप में, यदि आप पासवर्ड के बजाय सीधे कुंजी प्राप्त करते हैं, तो आप बहुत बेहतर होंगे। वांछित जानकारी कई गुना लीक हो सकती है, कोर डंप, एक डिबगर सत्र या स्वैप फाइलें सिर्फ कुछ उदाहरण हैं।

और जैसा कि यह पता चला है, ऐसा कुछ भी नहीं है जो आपको PrivateKeyमेमोरी से निजी जानकारी को साफ़ करने देता है , क्योंकि कोई भी एपीआई नहीं है जो आपको संबंधित जानकारी बनाने वाले बाइट्स को मिटा देता है।

यह एक बुरी स्थिति है, क्योंकि यह पेपर बताता है कि इस परिस्थिति का संभावित रूप से कैसे फायदा उठाया जा सकता है।

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


इसका एक तरीका यह है PrivateKeyकि इसके कार्यान्वयन का उपयोग वास्तव में अपनी निजी सामग्री को मेमोरी में लोड न करने के लिए किया जाता है : उदाहरण के लिए PKCS # 11 हार्डवेयर टोकन के माध्यम से। शायद PKCS # 11 का एक सॉफ्टवेयर कार्यान्वयन मैन्युअल रूप से मेमोरी की सफाई का ध्यान रख सकता है। शायद एनएसएस स्टोर (जो PKCS11जावा में स्टोर प्रकार के साथ इसके अधिकांश कार्यान्वयन को साझा करता है) की तरह कुछ का उपयोग करना बेहतर है। KeychainStore(OSX कुंजीस्टोर) भार अपने में निजी कुंजी की पूरी सामग्री PrivateKeyउदाहरणों, लेकिन यह करने की जरूरत नहीं होनी चाहिए। ( WINDOWS-MYविंडोज पर KeyStore क्या करता है यह निश्चित नहीं है ।)
ब्रूनो

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

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

@ ब्रूनो: दिलचस्प विचार, एक अतिरिक्त अप्रत्यक्ष परत जो स्मृति को साफ करने का ख्याल रखती है, वास्तव में इस पारदर्शी तरीके से हल करेगी। सॉफ्टवेयर कुंजी स्टोर के लिए PKCS # 11 रैपर लिखना पहले से ही कर सकता है?
नक्काशी

51

जैसा कि जॉन स्कीट कहता है, परावर्तन का उपयोग करने के अलावा कोई रास्ता नहीं है।

हालांकि, अगर प्रतिबिंब आपके लिए एक विकल्प है, तो आप ऐसा कर सकते हैं।

public static void main(String[] args) {
    System.out.println("please enter a password");
    // don't actually do this, this is an example only.
    Scanner in = new Scanner(System.in);
    String password = in.nextLine();
    usePassword(password);

    clearString(password);

    System.out.println("password: '" + password + "'");
}

private static void usePassword(String password) {

}

private static void clearString(String password) {
    try {
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        char[] chars = (char[]) value.get(password);
        Arrays.fill(chars, '*');
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

जब चला

please enter a password
hello world
password: '***********'

नोट: यदि स्ट्रिंग के चार [] को जीसी चक्र के एक भाग के रूप में कॉपी किया गया है, तो एक मौका है कि पिछली प्रति कहीं स्मृति में है।

यह पुरानी प्रति एक ढेर डंप में दिखाई नहीं देगी, लेकिन यदि आपके पास इस प्रक्रिया की कच्ची मेमोरी तक सीधी पहुंच है, तो आप इसे देख सकते हैं। सामान्य तौर पर आपको ऐसी पहुँच रखने से किसी को बचना चाहिए।


2
पासवर्ड की लंबाई को प्रिंट करने से रोकने के लिए भी कुछ करना बेहतर है, जो हमें मिलता है '***********'
chux -

@chux आप एक शून्य चौड़ाई वर्ण का उपयोग कर सकते हैं, हालांकि यह उपयोगी से अधिक भ्रामक हो सकता है। Unsafe का उपयोग किए बिना एक वर्ण सरणी की लंबाई को बदलना संभव नहीं है। ;)
पीटर लॉरी

5
जावा 8 के स्ट्रिंग डिडुप्लीकेशन के कारण, मुझे लगता है कि ऐसा कुछ करना काफी विनाशकारी हो सकता है ... आप अपने प्रोग्राम में अन्य स्ट्रिंग्स को क्लियर कर सकते हैं कि संयोग से पासवर्ड स्ट्रिंग का समान मूल्य था। संभावना नहीं है, लेकिन संभव ...
Jamp

1
@PeterLawrey यह JVM तर्क के साथ सक्षम होना चाहिए, लेकिन यह वहाँ है। इसके बारे में यहां पढ़ सकते हैं: blog.codecentric.de/en/2014/08/…
jamp

1
एक उच्च संभावना है कि पासवर्ड अभी भी Scannerआंतरिक बफर में है और जब से आप System.console().readPassword()कंसोल विंडो में पठनीय रूप में उपयोग नहीं करते हैं। लेकिन अधिकांश व्यावहारिक उपयोग के मामलों के लिए, usePasswordनिष्पादन की अवधि वास्तविक समस्या है। उदाहरण के लिए, किसी अन्य मशीन से संबंध बनाते समय, यह एक महत्वपूर्ण समय लेता है और एक हमलावर को बताता है कि यह ढेर में पासवर्ड की खोज करने का सही समय है। एकमात्र उपाय हमलावरों को ढेर मेमोरी पढ़ने से रोकने के लिए है ...
होल्गर

42

ये सभी कारण हैं, किसी को पासवर्ड के लिए स्ट्रिंग के बजाय एक चार [] सरणी का चयन करना चाहिए ।

1. चूंकि स्ट्रिंग्स जावा में अपरिवर्तनीय हैं, यदि आप पासवर्ड को सादे पाठ के रूप में संग्रहित करते हैं, तो यह मेमोरी में उपलब्ध होगा जब तक कि गारबेज कलेक्टर इसे साफ नहीं करता है, और चूंकि स्ट्रिंग को पुन: प्रयोज्य के लिए स्ट्रिंग पूल में उपयोग किया जाता है, इसलिए बहुत अधिक संभावना है कि यह हो सकता है लंबी अवधि के लिए स्मृति में बने रहें, जो सुरक्षा के लिए खतरा है।

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

2. जावा खुद ही JPPwordField की getPassword () पद्धति का उपयोग करने की सिफारिश करता है जो कि एक चार्ट [] देता है, इसके बजाय हटाए गए getText () विधि जो स्पष्ट पाठ में पासवर्ड लौटाता है सुरक्षा कारणों से। जावा टीम की सलाह का पालन करना और उनके खिलाफ जाने के बजाय मानकों का पालन करना अच्छा है।

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

String strPassword="Unknown";
char[] charPassword= new char[]{'U','n','k','w','o','n'};
System.out.println("String password: " + strPassword);
System.out.println("Character password: " + charPassword);

String password: Unknown
Character password: [C@110b053

इस ब्लॉग से संदर्भित । आशा है कि ये आपकी मदद करेगा।


10
यह बेमानी है। यह उत्तर @SrujanKumarGulla stackoverflow.com/a/14060804/1793718 द्वारा लिखे गए उत्तर का सटीक संस्करण है । कृपया कॉपी पेस्ट न करें या एक ही उत्तर को दो बार डुप्लिकेट न करें।
लकी

1.) के बीच क्या अंतर है। System.out.println ("चरित्र पासवर्ड:" + charPassword); और 2.) System.out.println (charPassword); क्योंकि यह आउटपुट के रूप में समान "अज्ञात" दे रहा है।
वैभव_शर्मा

3
@ लुकी दुर्भाग्य से आप जिस पुराने उत्तर से जुड़े थे, उसी ब्लॉग से इस उत्तर के रूप में साहित्यिक चोरी कर ली गई थी और अब इसे हटा दिया गया है। Meta.stackoverflow.com/questions/389144/… देखें । यह उत्तर केवल उसी ब्लॉग से कट और पेस्ट किया गया है और कुछ भी नहीं जोड़ा गया है, इसलिए इसे मूल स्रोत से जोड़ने वाली टिप्पणी होनी चाहिए।
स्कोमीसा

41

संपादित करें: सुरक्षा अनुसंधान के एक वर्ष के बाद इस उत्तर पर वापस आकर, मुझे एहसास हुआ कि यह दुर्भाग्यपूर्ण निहितार्थ बनाता है कि आप वास्तव में सादा पासवर्ड की तुलना करेंगे। कृपया नहीं। नमक के साथ एक सुरक्षित वन-वे हैश और उचित संख्या में पुनरावृत्तियों का उपयोग करें । लाइब्रेरी का उपयोग करने पर विचार करें: यह सामान सही होना कठिन है!

मूल उत्तर: इस तथ्य के बारे में क्या है कि String.equals () शॉर्ट-सर्किट मूल्यांकन का उपयोग करता है , और इसलिए यह समय के हमले के लिए असुरक्षित है? यह संभव नहीं है, लेकिन आप वर्णों के सही क्रम को निर्धारित करने के लिए सैद्धांतिक रूप से पासवर्ड की तुलना कर सकते हैं ।

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // Quits here if Strings are different lengths.
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // Quits here at first different character.
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

समय हमलों पर कुछ और संसाधन:


लेकिन यह चार [] तुलना में भी हो सकता है, कहीं न कहीं हम पासवर्ड सत्यापन में भी ऐसा ही करेंगे। तो तार कैसे [] स्ट्रिंग से बेहतर है?
मोहित कंवर

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

इसके अलावा प्लेन पासवर्ड की तुलना सही काम वैसे भी नहीं है, प्रलोभन का उपयोग करने Arrays.equalsके लिए char[]के लिए के रूप में उच्च के रूप में है String.equals। अगर किसी को परवाह है, तो वास्तविक पासवर्ड को एनकैप्सुलेट करने और मुद्दों की देखभाल करने के लिए एक समर्पित कुंजी वर्ग था - ओह प्रतीक्षा करें, असली सुरक्षा संकुल में कुंजी वर्ग समर्पित हैं, यह प्रश्नोत्तर केवल उनके बाहर की आदत के बारे में है , जैसे,JPasswordField उपयोग करने के लिए। char[]इसके बजाय String(जहां वास्तविक एल्गोरिदम का उपयोग byte[]वैसे भी होता है)।
होल्गर

सुरक्षा प्रासंगिक सॉफ़्टवेयर को sleep(secureRandom.nextInt())वैसे भी एक लॉगिन प्रयास को अस्वीकार करने से पहले कुछ करना चाहिए , जो न केवल समय के हमलों की संभावना को दूर कर रहा है, यह समकक्षों के बल के प्रयासों को भी विफल बनाता है।
होल्गर

36

ऐसा कुछ भी नहीं है कि चार सरणी आपको बनाम स्ट्रिंग देता है जब तक कि आप इसे उपयोग के बाद मैन्युअल रूप से साफ नहीं करते हैं, और मैंने किसी को वास्तव में ऐसा करते नहीं देखा है। तो मेरे लिए चार [] बनाम स्ट्रिंग की वरीयता थोड़ा अतिरंजित है।

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

हालाँकि, जावा हर समय बदलता रहता है, और कुछ डरावने फीचर्स जैसे कि स्ट्रिंग 8 के स्ट्रिंग डेडुप्लीकेशन फ़ीचर, बिना किसी जानकारी के स्ट्रिंग को इंटर्न कर सकते हैं। लेकिन वह एक अलग बातचीत है।


स्ट्रिंग-डिडुप्लीकेशन डरावना क्यों है? यह केवल तब लागू होता है जब समान सामग्री वाले कम से कम दो तार होते हैं, इसलिए इन दो पहले से ही समान तारों को एक ही सरणी को साझा करने देने से क्या खतरा पैदा होगा? या दूसरे तरीके से पूछने की अनुमति देता है: यदि कोई स्ट्रिंग-डिडुप्लीकेशन नहीं है, तो इस तथ्य से क्या फायदा होता है कि दोनों स्ट्रिंग्स का एक अलग सरणी (एक ही सामग्री का) है? या तो मामले में, उस सामग्री की एक सरणी होगी जो कम से कम लंबे समय तक जीवित रहेगी जब तक कि उस सामग्री का सबसे लंबा जीवित स्ट्रिंग जीवित है ...
Holger

@ ऐसा कुछ भी जो आपके नियंत्रण से बाहर हो, एक संभावित जोखिम है ... उदाहरण के लिए, यदि दो उपयोगकर्ताओं के पास एक ही पासवर्ड है तो यह अद्भुत सुविधा उन दोनों को सिंगल चार में संग्रहीत करेगी [] यह स्पष्ट कर रही है कि वे समान हैं, सुनिश्चित नहीं हैं कि एक बड़ा जोखिम लेकिन अभी भी
ओलेग मिखेव

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

@ पासवर्ड को सत्यापित करने के लिए इसे कुछ समय के लिए मेमोरी में क्लियर टेक्स्ट में रखना होगा, 10ms, भले ही इसके बारे में नमकीन हैश बनाना हो। फिर, अगर ऐसा होता है कि 10 एमएस के लिए भी दो समान पासवर्ड स्मृति में रखे गए हैं, तो कटौती लागू हो सकती है। यदि यह वास्तव में तार को नजरअंदाज कर देता है तो उन्हें अधिक समय तक स्मृति में रखा जाता है। सिस्टम जो महीनों तक रीस्टार्ट नहीं होता है, इनमें से बहुत सारे इकट्ठा हो जाएंगे। बस सिद्धांत है।
ओलेग मिखेव

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

30

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

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


यदि केवल JVM प्रश्न 1.6 है तो वे केवल GC'd होंगे। 1.7 से पहले, सभी तारों को परमिटेन में संग्रहीत किया गया था।
avgvstvs

@avgvstvs: "सभी तारों को पर्मगेन में संग्रहीत किया गया था" सिर्फ गलत है। केवल नजरबंद तारों को वहां संग्रहीत किया गया था और यदि वे कोड द्वारा संदर्भित स्ट्रिंग शाब्दिक से उत्पन्न नहीं थे, तो वे अभी भी एकत्र किए गए कचरा थे। बस उसके बारे मै सोच रहा था। यदि स्ट्रिंग्स आमतौर पर 1.7 से पहले जेवीएम में कभी भी जीसीड नहीं होते हैं, तो कोई भी जावा एप्लिकेशन कुछ मिनटों से अधिक कैसे बच सकता है?
होल्गर

@ होलजर यह गलत है। इंटर्नड stringsऔर Stringपूल (पहले इस्तेमाल किए गए तार के पूल) 1.7 से पहले पर्मेन में संग्रहीत किए गए थे। इसके अलावा, खंड 5.1 देखें: docs.oracle.com/javase/specs/jvms/se6/html/… JVM ने हमेशा Stringsयह देखने के लिए जाँच की कि क्या वे समान संदर्भ मान हैं, और आपके लिए कॉल करेंगे String.intern()। इसका परिणाम यह हुआ कि हर बार JVM ने समान स्ट्रिंग्स का पता लगाया constant_poolया ढेर में उन्हें पारगमेन में ले जाया गया। और मैंने 1.7 तक "रेंगने की अनुमति" के साथ कई अनुप्रयोगों पर काम किया। यह एक वास्तविक समस्या थी।
एवग्स्टव्स

इसलिए पुनरावृत्ति करने के लिए: 1.7 तक, constant_poolस्ट्रिप्स ढेर में शुरू हो गए, जब उनका उपयोग किया गया तो उन्हें अंदर डाल दिया गया था जो कि परमिट में स्थित था, और फिर अगर एक स्ट्रिंग को एक से अधिक बार इस्तेमाल किया गया था, तो इसे इंटर्न किया जाएगा।
एवग्स्टव्स

@avgvstvs: "पहले उपयोग किए गए स्ट्रिंग्स का पूल" नहीं है। आप पूरी तरह से अलग चीजों को एक साथ फेंक रहे हैं। एक रनटाइम स्ट्रिंग पूल है जिसमें स्ट्रिंग शाब्दिक और स्पष्ट रूप से आंतरिक स्ट्रिंग है, लेकिन कोई अन्य नहीं। और प्रत्येक वर्ग का अपना निरंतर पूल होता है जिसमें संकलन-समय स्थिरांक होता है। इन स्ट्रिंग्स को स्वचालित रूप से रनटाइम पूल में जोड़ा जाता है, लेकिन केवल ये , प्रत्येक स्ट्रिंग नहीं।
होल्गर

21

स्ट्रिंग अपरिवर्तनीय है और यह स्ट्रिंग पूल में जाती है। एक बार लिखे जाने के बाद इसे अधिलेखित नहीं किया जा सकता है।

char[] एक सरणी है जिसे आपको पासवर्ड का उपयोग करने के बाद लिखना चाहिए और इस तरह से यह किया जाना चाहिए:

char[] passw = request.getPassword().toCharArray()
if (comparePasswords(dbPassword, passw) {
 allowUser = true;
 cleanPassword(passw);
 cleanPassword(dbPassword);
 passw=null;
}

private static void cleanPassword (char[] pass) {

Arrays.fill(pass, '0');
}

एक परिदृश्य जहां हमलावर इसका इस्तेमाल कर सकता है वह क्रैशडंप है - जब जेवीएम दुर्घटनाग्रस्त हो जाता है और मेमोरी डंप उत्पन्न करता है - तो आप पासवर्ड देख पाएंगे।

यह जरूरी नहीं कि एक दुर्भावनापूर्ण बाहरी हमलावर हो। यह एक समर्थन उपयोगकर्ता हो सकता है जिसके पास मॉनिटरिंग उद्देश्यों के लिए सर्वर तक पहुंच हो। वह एक क्रैशडंप में जा सकता है और पासवर्ड ढूंढ सकता है।


2
ch = null; आप ऐसा नहीं कर सकते
युगेर्टन

लेकिन request.getPassword()पहले से ही स्ट्रिंग नहीं बनाता है और इसे पूल में जोड़ता है?
Tvde1

1
ch = '0'स्थानीय परिवर्तनशील परिवर्तन ch; इसका सरणी पर कोई प्रभाव नहीं है। और आपका उदाहरण वैसे भी व्यर्थ है, आप एक ऐसे स्ट्रिंग उदाहरण से शुरू करते हैं जिस toCharArray()पर आप कॉल करते हैं, एक नया सरणी बनाते हैं और यहां तक ​​कि जब आप नए सरणी को सही ढंग से अधिलेखित कर देते हैं, तो यह स्ट्रिंग आवृत्ति को नहीं बदलता है, इसलिए स्ट्रिंग का उपयोग करने पर इसका कोई लाभ नहीं है उदाहरण।
होल्गर

@ होल्गर धन्यवाद। वर्ण सरणी सफाई कोड को ठीक किया।
एसीवी

3
आप बस का उपयोग कर सकते हैंArrays.fill(pass, '0');
Holger

18

छोटा और सीधा उत्तर होगा क्योंकि char[]परस्पर परिवर्तनशील हैString वस्तुएं नहीं हैं।

Stringsजावा में अपरिवर्तनीय वस्तुएँ हैं। यही कारण है कि उन्हें एक बार बनाया नहीं जा सकता है, और इसलिए उनकी सामग्री को स्मृति से निकालने का एकमात्र तरीका उन्हें कचरा एकत्र करना है। यह तभी होगा जब ऑब्जेक्ट द्वारा मुक्त की गई मेमोरी को ओवरराइट किया जा सकता है, और डेटा चला जाएगा।

अब जावा में कचरा संग्रह किसी भी गारंटीकृत अंतराल पर नहीं होता है। String प्रकार मेमोरी लंबे समय तक बनी रह सकती है, और यदि इस दौरान कोई प्रक्रिया क्रैश हो जाती है, तो स्ट्रिंग की सामग्री मेमोरी डंप या कुछ लॉग में समाप्त हो सकती है।

एक चरित्र सरणी के साथ , आप पासवर्ड पढ़ सकते हैं, जैसे ही आप कर सकते हैं उसके साथ काम करना समाप्त कर सकते हैं, और फिर तुरंत सामग्री को बदल सकते हैं।


@fallenidol बिलकुल नहीं। ध्यान से पढ़ें और आप अंतर पाएंगे।
प्रीतम बैनर्जी

12

जावा में स्ट्रिंग अपरिवर्तनीय है। इसलिए जब भी कोई स्ट्रिंग बनाई जाती है, तो यह तब तक मेमोरी में बनी रहेगी जब तक कि यह कचरा इकट्ठा न हो जाए। तो जिस किसी के पास मेमोरी तक पहुंच है, वह स्ट्रिंग के मूल्य को पढ़ सकता है।
यदि स्ट्रिंग के मूल्य को संशोधित किया जाता है, तो यह एक नया स्ट्रिंग बनाना समाप्त कर देगा। तो मूल मूल्य और संशोधित मूल्य दोनों मेमोरी में रहते हैं जब तक कि यह कचरा एकत्र नहीं किया जाता है।

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

सुरक्षा चिंता के कारण पासवर्ड को चरित्र सरणी के रूप में संग्रहीत करना बेहतर है।


2

यह बहस का विषय है कि क्या आपको स्ट्रिंग का उपयोग करना चाहिए या इस उद्देश्य के लिए चार [] का उपयोग करना चाहिए क्योंकि दोनों के अपने फायदे और नुकसान हैं। यह इस बात पर निर्भर करता है कि उपयोगकर्ता को क्या चाहिए।

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

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

उपरोक्त परिस्थितियों के आधार पर, कोई भी विचार कर सकता है कि स्ट्रिंग के साथ जाना है या अपनी आवश्यकताओं के लिए चार [] के साथ जाना है।


0

केस स्ट्रिंग:

    String password = "ill stay in StringPool after Death !!!";
    // some long code goes
    // ...Now I want to remove traces of password
    password = null;
    password = "";
    // above attempts wil change value of password
    // but the actual password can be traced from String pool through memory dump, if not garbage collected

मामला चार ARRAY:

    char[] passArray = {'p','a','s','s','w','o','r','d'};
    // some long code goes
    // ...Now I want to remove traces of password
    for (int i=0; i<passArray.length;i++){
        passArray[i] = 'x';
    }
    // Now you ACTUALLY DESTROYED traces of password form memory
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.