कॉन्फ़िगरेशन फ़ाइलों में पासवर्ड एन्क्रिप्ट करें? [बन्द है]


130

मेरे पास एक प्रोग्राम है जो एक कॉन्फ़िगरेशन फ़ाइल से सर्वर की जानकारी पढ़ता है और उस कॉन्फ़िगरेशन में पासवर्ड को एन्क्रिप्ट करना चाहता है जिसे मेरे प्रोग्राम द्वारा पढ़ा जा सकता है और डिक्रिप्ट किया जा सकता है।

requirments:

  • फाइल में स्टोर किए जाने वाले प्लेनटेक्स्ट पासवर्ड को एन्क्रिप्ट करें
  • मेरे प्रोग्राम से फ़ाइल से पढ़े गए एन्क्रिप्टेड पासवर्ड को डिक्रिप्ट करें

मैं कैसे इस बारे में जाऊँगा इस पर कोई प्रतिक्रिया? मैं अपनी खुद की एल्गोरिथ्म लिखने के बारे में सोच रहा था, लेकिन मुझे लगता है कि यह बहुत असुरक्षित होगा।

जवाबों:


172

ऐसा करने का एक सरल तरीका जावा में पासवर्ड आधारित एन्क्रिप्शन का उपयोग करना है। यह आपको पासवर्ड का उपयोग करके पाठ को एन्क्रिप्ट और डिक्रिप्ट करने की अनुमति देता है।

यह मूल रूप से एक आरंभ मतलब है javax.crypto.Cipherएल्गोरिथ्म के साथ "AES/CBC/PKCS5Padding"और से एक महत्वपूर्ण हो रही javax.crypto.SecretKeyFactoryके साथ "PBKDF2WithHmacSHA512"एल्गोरिथ्म।

यहां एक कोड उदाहरण (कम सुरक्षित एमडी 5-आधारित संस्करण को बदलने के लिए अद्यतन किया गया है):

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class ProtectedConfigFile {

    public static void main(String[] args) throws Exception {
        String password = System.getProperty("password");
        if (password == null) {
            throw new IllegalArgumentException("Run with -Dpassword=<password>");
        }

        // The salt (probably) can be stored along with the encrypted data
        byte[] salt = new String("12345678").getBytes();

        // Decreasing this speeds down startup time and can be useful during testing, but it also makes it easier for brute force attackers
        int iterationCount = 40000;
        // Other values give me java.security.InvalidKeyException: Illegal key size or default parameters
        int keyLength = 128;
        SecretKeySpec key = createSecretKey(password.toCharArray(),
                salt, iterationCount, keyLength);

        String originalPassword = "secret";
        System.out.println("Original password: " + originalPassword);
        String encryptedPassword = encrypt(originalPassword, key);
        System.out.println("Encrypted password: " + encryptedPassword);
        String decryptedPassword = decrypt(encryptedPassword, key);
        System.out.println("Decrypted password: " + decryptedPassword);
    }

    private static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
        PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
        SecretKey keyTmp = keyFactory.generateSecret(keySpec);
        return new SecretKeySpec(keyTmp.getEncoded(), "AES");
    }

    private static String encrypt(String property, SecretKeySpec key) throws GeneralSecurityException, UnsupportedEncodingException {
        Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        pbeCipher.init(Cipher.ENCRYPT_MODE, key);
        AlgorithmParameters parameters = pbeCipher.getParameters();
        IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
        byte[] cryptoText = pbeCipher.doFinal(property.getBytes("UTF-8"));
        byte[] iv = ivParameterSpec.getIV();
        return base64Encode(iv) + ":" + base64Encode(cryptoText);
    }

    private static String base64Encode(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    private static String decrypt(String string, SecretKeySpec key) throws GeneralSecurityException, IOException {
        String iv = string.split(":")[0];
        String property = string.split(":")[1];
        Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
        return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
    }

    private static byte[] base64Decode(String property) throws IOException {
        return Base64.getDecoder().decode(property);
    }
}

एक समस्या बनी हुई है: आपको पासवर्ड को एन्क्रिप्ट करने के लिए उपयोग किए जाने वाले पासवर्ड को कहां संग्रहीत करना चाहिए? आप इसे स्रोत फ़ाइल में संग्रहीत कर सकते हैं और इसे बाधित कर सकते हैं, लेकिन इसे फिर से खोजना बहुत कठिन नहीं है। वैकल्पिक रूप से, आप इसे जावा प्रॉपर्टी ( -DpropertyProtectionPassword=...) शुरू करने पर सिस्टम प्रॉपर्टी के रूप में दे सकते हैं ।

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


3
कोड उदाहरण के लिए धन्यवाद, यह बहुत ज्यादा है कि मैंने इसे कैसे किया। जिस पासवर्ड से मैं उसी समस्या में भाग गया था, उस पासवर्ड की सुरक्षा के संबंध में, मैंने अभी के लिए यह विधि स्थगित कर दी, लेकिन havnt अभी तक एक स्वीकार्य समाधान के साथ आया, आपके सुझावों के लिए धन्यवाद।
पेटी बी

7
"वैकल्पिक रूप से, जब आप जावा प्रक्रिया शुरू करते हैं तो आप इसे एक सिस्टम प्रॉपर्टी के रूप में दे सकते हैं (-प्रोपरेटरीप्रोटेक्शनपासवर्ड = ...)"। ध्यान दें कि इससे "ps फ़ैक्स" (GNU / Linux) / UNIX का उपयोग करके पासवर्ड निकालना संभव होगा।
जेटीएक्स

7
@ जब आप परिणामी मान को टेक्स्ट-फ़ाइल या स्ट्रिंग-आधारित डेटाबेस कॉलम, या समान में संग्रहीत करने की अनुमति देने के लिए Base64 को एन्कोड करना आम बात है।
आरबी।

4
@ V.7 नप। MD5 पासवर्ड हैशिंग के लिए बिल्कुल सुरक्षित नहीं है और इसे इस उद्देश्य के लिए डिज़ाइन नहीं किया गया था। उसके लिए कभी उपयोग न करें। इन दिनों, आर्गन 2 सबसे अच्छा है। देखें owasp.org/index.php/Password_Storage_Cheat_Sheet और paragonie.com/blog/2016/02/how-safely-store-password-in-2016
Kimball रॉबिन्सन

3
इस तरह बहुत बेहतर। बेशक एक सुरक्षित यादृच्छिक नमक और 40K के (रूढ़िवादी, कम अंत) की एक पुनरावृत्ति गिनती अच्छी होगी, लेकिन कम से कम आपने इन चीजों को टिप्पणियों में इंगित किया है और PBKDF2 और AES / CBC निश्चित सुधार हैं। मुझे लगता है कि यह बहुत अच्छा है कि आपने इसे कैसे संभाला, उत्तर को अपडेट करके; मैं चेतावनी को हटा दूँगा। अपनी टिप्पणी को वोट किया ताकि लोग अपडेटेड कोड को खोजने के लिए आश्चर्यचकित न हों (वे उस पुराने कोड को खोजने के लिए संपादन को देख सकते हैं जो मुझे लगता है)। अपनी पुरानी टिप्पणियों को साफ करने के लिए एक अच्छा विचार हो सकता है।
मार्टेन बॉड्यूज

20

हां, अपना खुद का एल्गोरिदम जरूर लिखें। जावा में बहुत सारी क्रिप्टोग्राफी एपीआई हैं।

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


4
एक KeyStore का उपयोग करने के लिए +1! यदि आप जार फ़ाइल में कुंजी संग्रहीत कर रहे हैं तो यह आक्षेप से अधिक कुछ नहीं है।
नाइनस्ड

2
यदि सभी आवश्यक है कि पासवर्ड स्पष्ट पाठ में संग्रहीत नहीं है, तो कीस्टोर्स ओवरकिल हैं।
थोरबजोरन रावन एंडरसन

20

की जाँच करें jasypt है, जो एक पुस्तकालय न्यूनतम प्रयास के साथ बुनियादी एन्क्रिप्शन क्षमताओं करता है।


16

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

इस तरह, कोई कष्टप्रद क्रिप्टोग्राफी ओवरहेड नहीं है और आपके पास अभी भी एक पासवर्ड है जो सुरक्षित है।

संपादित करें: मैं यह मान रहा हूं कि आप एक विश्वसनीय वातावरण के बाहर अपने एप्लिकेशन कॉन्फ़िगरेशन का निर्यात नहीं कर रहे हैं (जो मुझे यकीन नहीं है कि किसी भी अर्थ में होगा, प्रश्न दिया गया):


4

अच्छी तरह से मास्टर पासवर्ड की समस्याओं को हल करने के लिए - सबसे अच्छा तरीका पासवर्ड को कहीं भी संग्रहीत नहीं करना है, आवेदन को अपने लिए पासवर्ड एन्क्रिप्ट करना चाहिए - ताकि केवल यह उन्हें डिक्रिप्ट कर सके। इसलिए अगर मैं एक .config फ़ाइल का उपयोग कर रहा था तो मैं निम्नलिखित कार्य करूंगा , mySettings.config :

encryptTheseKeys = secretKey, anotherSecret

secretKey = unprotectedPasswordThatIputHere

anotherSecret = anotherPass

someKey = unprotectedSettingIdontCareAbout

इसलिए मैं इनक्रिप्ट्स में उल्लिखित कुंजियों में पढ़ूंगा, उन पर ऊपर से ब्रॉडवॉल्स उदाहरण लागू करें और उन्हें किसी प्रकार के मार्कर के साथ फाइल में वापस लिखें ( क्रिप्ट को कहने दें:) एप्लिकेशन को यह नहीं करने दें फिर से, आउटपुट इस तरह दिखेगा:

encryptTheseKeys = secretKey, anotherSecret

secretKey = क्रिप्ट: ii4jfj304fjhfj934fouh938

अन्यसेक्रेट = क्रिप्ट: jd48jofh48h

someKey = unprotectedSettingIdontCareAbout

बस मूल को अपने सुरक्षित स्थान पर रखना सुनिश्चित करें ...


2
हाँ, यह 3 साल पहले से है। मास्टर कुंजी से बचने के लिए, हमने हमारे आंतरिक CA से जारी RSA कुंजी का उपयोग करके समाप्त कर दिया। निजी कुंजी तक पहुंच मशीन हार्डवेयर के फिंगर प्रिंट के साथ एन्क्रिप्टेड होने से सुरक्षित है।
पेटी बी

मुझे लगता है, बहुत ठोस लगता है। अच्छा।
user1007231

@ user1007231 - कहां रखें - "मूल को अपने सुरक्षित स्थान पर रखना सुनिश्चित करें ..."?
नैनोसॉफ्ट

@PeteyB - समझ में नहीं आया? क्या आप मुझे कुछ लिंक्स की ओर इशारा कर सकते हैं जो मुझे बता सकते हैं। धन्यवाद
nanosoft

@nanosoft - एक "एजिस सिक्योर की USB" प्राप्त करें और एक टेक्स्ट डॉक में या अपने बटुए में कागज पर स्टोर करें
user1007231

4

बड़े बिंदु, और कमरे में हाथी और वह सब, यह है कि यदि आपका आवेदन पासवर्ड पकड़ सकता है, तो बॉक्स तक पहुंच वाले एक हैकर को भी पकड़ सकता है!

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

हालाँकि, इस स्तर की झुंझलाहट के साथ भी, यदि कोई हैकर रूट एक्सेस प्राप्त करने का प्रबंधन करता है (या यहां तक ​​कि आपके एप्लिकेशन को चलाने वाले उपयोगकर्ता के रूप में भी एक्सेस करता है), तो वह मेमोरी को डंप कर सकता है और वहां पासवर्ड ढूंढ सकता है।

यह सुनिश्चित करने की बात है, पूरी कंपनी को उत्पादन सर्वर (और इस तरह पासवर्ड) तक पहुंचने की अनुमति नहीं है, और सुनिश्चित करें कि इस बॉक्स को क्रैक करना असंभव है!


असली उपाय यह है कि आप अपनी निजी कुंजी कहीं और स्टोर करें, जैसे कार्ड या एचएसएम: en.wikipedia.org/wiki/Hardware_security_module
atom88

1

ESAPI एन्क्रिप्शन विधियों का उपयोग करने का प्रयास करें। इसे कॉन्फ़िगर करना आसान है और आप आसानी से अपनी चाबियाँ भी बदल सकते हैं।

http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html

आप

1) एन्क्रिप्ट 2) डिक्रिप्ट 3) साइन 4) अनसाइन 5) हैशिंग 6) समय आधारित हस्ताक्षर और बहुत कुछ सिर्फ एक लाइब्रेरी के साथ।


1

जेटी में उपलब्ध विन्यास फाइल में पासवर्ड (या हैश) को देखने के लिए देखें और विचार करें कि क्या OBF एन्कोडिंग आपके लिए उपयोगी हो सकती है। फिर स्रोत में देखें कि यह कैसे किया जाता है।

http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html


0

इस बात पर निर्भर करता है कि आपको कॉन्फ़िगरेशन फ़ाइलों की कितनी सुरक्षित आवश्यकता है या आपका एप्लिकेशन कितना विश्वसनीय है, http://activemq.apache.org/encrypted-passwords.html आपके लिए एक अच्छा समाधान हो सकता है।

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


HSM का उपयोग करना आदर्श तरीका है: en.wikipedia.org/wiki/Hardware_security_module
atom88

-8

यदि आप जावा 8 का उपयोग कर रहे हैं तो आंतरिक बेस 64 एनकोडर और डिकोडर के उपयोग को प्रतिस्थापित करके बचा जा सकता है

return new BASE64Encoder().encode(bytes);

साथ में

return Base64.getEncoder().encodeToString(bytes);

तथा

return new BASE64Decoder().decodeBuffer(property);

साथ में

return Base64.getDecoder().decode(property);

ध्यान दें कि यह समाधान आपके डेटा की सुरक्षा नहीं करता है क्योंकि डिक्रिप्ट करने के तरीके उसी स्थान पर संग्रहीत हैं। यह सिर्फ इसे तोड़ने के लिए और अधिक कठिन बनाता है। मुख्य रूप से यह इसे प्रिंट करने और गलती से हर किसी को दिखाने से बचता है।


26
Base64 एन्क्रिप्शन नहीं है।
जॉलीके

1
बेस 64 एनक्रिप्शन नहीं है और यह सबसे खराब उदाहरण है जो आप प्रदान कर सकते हैं ... बहुत से लोग मानते हैं कि बेस 64 एक एन्क्रिप्शन अल्गॉर्टिह्म है, इसलिए उन्हें भ्रमित न करने के लिए बेहतर है ...
रोबॉट

ध्यान दें कि स्रोत फ़ाइल के शीर्ष में डिकोड () विधि वास्तविक एन्क्रिप्शन करती है। हालाँकि, इस बेस 64 एन्कोडिंग और डिकोडिंग को इस फ़ंक्शन को पास करने के लिए एक स्ट्रिंग बाइट्स से बदलने की आवश्यकता होती है, जिसे वह उपयोग कर सकता है (एक बाइट सरणी बाइट [])
atom88
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.