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




string security (14)

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

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

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

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


जबकि यहां अन्य सुझाव मान्य हैं, एक और अच्छा कारण है। सादा 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: [[email protected]

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

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

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

यह एक बुरी स्थिति है, क्योंकि यह paper वर्णन करता है कि इस परिस्थिति का संभावित रूप से शोषण कैसे किया जा सकता है।

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


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

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

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

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


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

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

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


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

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

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


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

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

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


जॉन स्कीट के अनुसार, प्रतिबिंब का उपयोग करके छोड़कर कोई रास्ता नहीं है।

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

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: '***********'

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

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


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

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

2. जावा स्वयं जेपीएस्वर्डफिल्ड की getPassword () विधि का उपयोग करने की सिफारिश करता है जो एक char [] और बहिष्कृत 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: [[email protected]

संदर्भ: http://javarevisited.blogspot.com/2012/03/why-character-array-is-better-than.html उम्मीद है कि इससे मदद मिलती है।


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

अद्यतन करें

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

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

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


संक्षिप्त और सीधा जवाब होगा क्योंकि ऑब्जेक्ट्स नहीं होने char[]पर उत्परिवर्तनीय है String

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

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

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


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

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


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

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

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

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

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

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


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

मूल उत्तर: इस तथ्य के बारे में क्या है कि 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;
}

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





char