एंड्रॉइड एप्लिकेशन में उपयोगकर्ता सेटिंग्स को स्टोर करने का सबसे उपयुक्त तरीका क्या है


308

मैं एक एप्लिकेशन बना रहा हूं जो उपयोगकर्ता नाम / पासवर्ड का उपयोग करके सर्वर से जुड़ता है और मैं विकल्प "पासवर्ड सहेजें" को सक्षम करना चाहूंगा, ताकि उपयोगकर्ता को हर बार एप्लिकेशन शुरू होने पर पासवर्ड टाइप न करना पड़े।

मैं इसे साझा प्रेफरेंस के साथ करने की कोशिश कर रहा था लेकिन यकीन नहीं होता कि यह सबसे अच्छा समाधान है।

मैं Android एप्लिकेशन में उपयोगकर्ता मान / सेटिंग्स को संग्रहीत करने के किसी भी सुझाव की सराहना करूंगा।

जवाबों:


233

सामान्य रूप से साझा किए गए प्राथमिकताओं में आपकी प्राथमिकताएँ संग्रहीत करने के लिए सबसे अच्छी शर्त है, इसलिए सामान्य तौर पर मैं आवेदन और उपयोगकर्ता सेटिंग्स को बचाने के लिए उस दृष्टिकोण की सिफारिश करूंगा।

यहाँ चिंता का एकमात्र क्षेत्र यह है कि आप क्या बचत कर रहे हैं। पासवर्ड हमेशा स्टोर करने के लिए एक मुश्किल काम है, और मैं विशेष रूप से उन्हें स्पष्ट पाठ के रूप में संग्रहीत करने से सावधान रहूंगा। एंड्रॉइड आर्किटेक्चर ऐसा है कि आपके एप्लिकेशन के SharedPreferences अन्य एप्लिकेशनों को मानों को एक्सेस करने में सक्षम होने से रोकने के लिए सैंडबॉक्स किए गए हैं, इसलिए वहां कुछ सुरक्षा है, लेकिन किसी फ़ोन पर भौतिक एक्सेस संभवतः मानों तक पहुंच की अनुमति दे सकता है।

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


3
क्या आप बता सकते हैं कि सैंडबॉक्स से आपका क्या मतलब है?
अभिजीत

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

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

1
प्रति android-developers.blogspot.com/2013/02/... , उपयोगकर्ता क्रेडेंशियल्स MODE_PRIVATE ध्वज सेट के साथ संग्रहीत और आंतरिक संग्रहण में संग्रहीत किया जाना चाहिए (स्थानीय रूप से अंत में हमले के लिए खुला पासवर्ड किसी भी प्रकार का भंडारण के बारे में एक ही कैविएट्स के साथ)। कहा कि, MODE_PRIVATEस्थानीय स्तर पर संग्रहीत डेटा को प्रभावी बनाने के लिए प्रभावशीलता के संदर्भ में, आंतरिक भंडारण पर बनाई गई फ़ाइल के साथ समान करने के लिए समान साझाकरण के साथ उपयोग कर रहा है?
क्विक्स

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

211

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

हालाँकि, ऐसा कहा जा रहा है, ऐसा लगता है कि उन मोबाइल अनुप्रयोगों की पहचान करने के लिए एक प्रचार पहल की जा रही है जो अपने पासवर्ड को SharedPreferences में क्लियरटेक्स्ट में संग्रहीत करते हैं और उन अनुप्रयोगों पर प्रतिकूल प्रकाश डालते हैं। कुछ उदाहरणों के लिए http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/ और http://viaforensics.com/appwatchdog देखें ।

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

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

final SharedPreferences prefs = new ObscuredSharedPreferences( 
    this, this.getSharedPreferences(MY_PREFS_FILE_NAME, Context.MODE_PRIVATE) );

// eg.    
prefs.edit().putString("foo","bar").commit();
prefs.getString("foo", null);

यहाँ कक्षा के लिए कोड है:

/**
 * Warning, this gives a false sense of security.  If an attacker has enough access to
 * acquire your password store, then he almost certainly has enough access to acquire your
 * source binary and figure out your encryption key.  However, it will prevent casual
 * investigators from acquiring passwords, and thereby may prevent undesired negative
 * publicity.
 */
public class ObscuredSharedPreferences implements SharedPreferences {
    protected static final String UTF8 = "utf-8";
    private static final char[] SEKRIT = ... ; // INSERT A RANDOM PASSWORD HERE.
                                               // Don't use anything you wouldn't want to
                                               // get out there if someone decompiled
                                               // your app.


    protected SharedPreferences delegate;
    protected Context context;

    public ObscuredSharedPreferences(Context context, SharedPreferences delegate) {
        this.delegate = delegate;
        this.context = context;
    }

    public class Editor implements SharedPreferences.Editor {
        protected SharedPreferences.Editor delegate;

        public Editor() {
            this.delegate = ObscuredSharedPreferences.this.delegate.edit();                    
        }

        @Override
        public Editor putBoolean(String key, boolean value) {
            delegate.putString(key, encrypt(Boolean.toString(value)));
            return this;
        }

        @Override
        public Editor putFloat(String key, float value) {
            delegate.putString(key, encrypt(Float.toString(value)));
            return this;
        }

        @Override
        public Editor putInt(String key, int value) {
            delegate.putString(key, encrypt(Integer.toString(value)));
            return this;
        }

        @Override
        public Editor putLong(String key, long value) {
            delegate.putString(key, encrypt(Long.toString(value)));
            return this;
        }

        @Override
        public Editor putString(String key, String value) {
            delegate.putString(key, encrypt(value));
            return this;
        }

        @Override
        public void apply() {
            delegate.apply();
        }

        @Override
        public Editor clear() {
            delegate.clear();
            return this;
        }

        @Override
        public boolean commit() {
            return delegate.commit();
        }

        @Override
        public Editor remove(String s) {
            delegate.remove(s);
            return this;
        }
    }

    public Editor edit() {
        return new Editor();
    }


    @Override
    public Map<String, ?> getAll() {
        throw new UnsupportedOperationException(); // left as an exercise to the reader
    }

    @Override
    public boolean getBoolean(String key, boolean defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Boolean.parseBoolean(decrypt(v)) : defValue;
    }

    @Override
    public float getFloat(String key, float defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Float.parseFloat(decrypt(v)) : defValue;
    }

    @Override
    public int getInt(String key, int defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Integer.parseInt(decrypt(v)) : defValue;
    }

    @Override
    public long getLong(String key, long defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Long.parseLong(decrypt(v)) : defValue;
    }

    @Override
    public String getString(String key, String defValue) {
        final String v = delegate.getString(key, null);
        return v != null ? decrypt(v) : defValue;
    }

    @Override
    public boolean contains(String s) {
        return delegate.contains(s);
    }

    @Override
    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
        delegate.registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }

    @Override
    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
        delegate.unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }




    protected String encrypt( String value ) {

        try {
            final byte[] bytes = value!=null ? value.getBytes(UTF8) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.Secure.ANDROID_ID).getBytes(UTF8), 20));
            return new String(Base64.encode(pbeCipher.doFinal(bytes), Base64.NO_WRAP),UTF8);

        } catch( Exception e ) {
            throw new RuntimeException(e);
        }

    }

    protected String decrypt(String value){
        try {
            final byte[] bytes = value!=null ? Base64.decode(value,Base64.DEFAULT) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.Secure.ANDROID_ID).getBytes(UTF8), 20));
            return new String(pbeCipher.doFinal(bytes),UTF8);

        } catch( Exception e) {
            throw new RuntimeException(e);
        }
    }

}

3
FYI Base64 API स्तर 8 (2.2) और बाद में उपलब्ध है। आप पहले के OS के लिए iharder.sourceforge.net/current/java/base64 या कुछ और का उपयोग कर सकते हैं ।
एमएमबी

34
हां, मैंने यह लिखा है। बेझिझक उपयोग करें, कोई भी आवश्यक नहीं है
एमएमबी

8
मैं आपसे सहमत हुँ। लेकिन अगर पासवर्ड केवल सर्वर पर उपयोग किया जाता है, तो सार्वजनिक / निजी कुंजी एन्क्रिप्शन का उपयोग क्यों न करें? पासवर्ड सहेजते समय क्लाइंट पर सार्वजनिक कुंजी। क्लाइंट को कभी भी स्पष्ट टेक्स्ट पासवर्ड दोबारा नहीं पढ़ना होगा, है ना? सर्वर फिर इसे निजी कुंजी के साथ डिक्रिप्ट कर सकता है। यहां तक ​​कि अगर कोई आपके ऐप स्रोत कोड के माध्यम से जाता है, तो वे पासवर्ड प्राप्त नहीं कर सकते हैं, सिवाय इसके कि वे आपके सर्वर को हैक करें और निजी कुंजी प्राप्त करें।
पैट्रिक बूस

4
मैंने इस कोड में कुछ विशेषताएं जोड़ी हैं और इसे github.com/RightHandedMonkey/WorxForUs_Library/blob/master/src/… पर github पर रखा है । अब यह एन्क्रिप्टेड एक गैर-एन्क्रिप्टेड वरीयताओं को माइग्रेट करने का काम करता है। इसके अलावा, यह रनटाइम में कुंजी उत्पन्न करता है, इसलिए ऐप को डिकंपोज करने से कुंजी जारी नहीं होती है।
राइटहैंडमेडकी

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

29

Android गतिविधि में किसी एकल वरीयता को संग्रहीत करने के सबसे सरल तरीके के बारे में कुछ ऐसा करना है:

Editor e = this.getPreferences(Context.MODE_PRIVATE).edit();
e.putString("password", mPassword);
e.commit();

यदि आप इन की सुरक्षा के बारे में चिंतित हैं तो आप इसे संग्रहीत करने से पहले पासवर्ड को हमेशा एन्क्रिप्ट कर सकते हैं।


9
मैं इस सरलीकृत दृष्टिकोण के बारे में आपसे अधिक सहमत नहीं हो सका; हालाँकि, आपको हमेशा आपके द्वारा संग्रहीत पासवर्ड की सुरक्षा के बारे में चिंतित होना चाहिए? आपके आवेदन के आधार पर, आपके पास चोरी की गई व्यक्तिगत जानकारी के लिए संभावित दायित्व हैं। बस इस बात की ओर इशारा करते हुए कि कोई भी व्यक्ति वास्तविक पासवर्ड को बैंक खातों या ऐसी ही किसी महत्वपूर्ण चीज़ में संग्रहीत करने की कोशिश कर रहा है। मैं फिर भी आपको वोट देता हूं।
जबकि-ई

1
आप पासवर्ड संग्रहीत करने वाली कुंजी को कहां संग्रहीत करेंगे? यदि साझा प्राथमिकताएं अन्य उपयोगकर्ताओं द्वारा सुलभ हैं, तो कुंजी है।
OrhanC1

@ OrhanC1 आपको जवाब मिला?
eRaisedToX

10

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

मैंने पहले इसे पूरा करने के लिए "छिपी" वरीयता को जोड़ने का सुझाव दिया था। यह निश्चित रूप से सबसे अच्छा तरीका नहीं है। मैं दो अन्य विकल्प प्रस्तुत करने जा रहा हूं जिन्हें मैं अधिक व्यवहार्य मानता हूं।

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

  public boolean onPreferenceChange(Preference preference, Object newValue) {
      // get our "secure" shared preferences file.
      SharedPreferences secure = context.getSharedPreferences(
         "SECURE",
         Context.MODE_PRIVATE
      );
      String encryptedText = null;
      // encrypt and set the preference.
      try {
         encryptedText = SimpleCrypto.encrypt(Preferences.SEED,(String)newValue);

         Editor editor = secure.getEditor();
         editor.putString("encryptedPassword",encryptedText);
         editor.commit();
      }
      catch (Exception e) {
         e.printStackTrace();
      }
      // always return false.
      return false; 
   }

दूसरा तरीका, और जिस तरह से मैं अब पसंद करता हूं, वह है अपनी स्वयं की कस्टम वरीयता बनाना, EditTextPreference, @ ओवरराइडिंग setText()और getText()विधियों का विस्तार करना , ताकि setText()पासवर्ड को एन्क्रिप्ट किया जाए , और getText()अशक्त हो।


मुझे पता है कि यह बहुत पुराना है, लेकिन क्या आप अपने कोड को EditTextPreference के कस्टम संस्करण के लिए पोस्ट करना चाहेंगे?
रेनीपेट

कोई बात नहीं, मुझे यहाँ एक प्रयोग करने योग्य नमूना मिला। groupfor.google.com/forum/# ​​.topic/android - developers/pMYNEVXMa6M और मैंने इसे अभी काम कर लिया है। इस दृष्टिकोण का सुझाव देने के लिए धन्यवाद।
RenniePet

6

ठीक है; यह उत्तर देने में कुछ समय लगा है क्योंकि यह मिश्रित है, लेकिन यहां कुछ सामान्य उत्तर हैं। मैंने पागलों की तरह इस पर शोध किया और एक अच्छे उत्तर का निर्माण करना कठिन था

  1. MODE_PRIVATE विधि को आम तौर पर सुरक्षित माना जाता है, यदि आप मानते हैं कि उपयोगकर्ता ने डिवाइस को रूट नहीं किया था। आपका डेटा फ़ाइल सिस्टम के एक हिस्से में सादे पाठ में संग्रहीत किया जाता है जिसे केवल मूल कार्यक्रम द्वारा एक्सेस किया जा सकता है। यह आसान रूट किए गए डिवाइस पर किसी अन्य ऐप के साथ पासवर्ड को हथियाने वाला है। फिर, क्या आप रूट किए गए उपकरणों का समर्थन करना चाहते हैं?

  2. एईएस अभी भी सबसे अच्छा एन्क्रिप्शन है जो आप कर सकते हैं। यह देखने के लिए याद रखें कि क्या आपने एक नया कार्यान्वयन शुरू कर रहा है अगर यह पोस्ट करने के बाद से कुछ समय हो गया है। इसके साथ सबसे बड़ा मुद्दा "एन्क्रिप्शन कुंजी के साथ क्या करना है?"

तो, अब हम "कुंजी के साथ क्या करना है?" हिस्से। यह कठिन भाग है। कुंजी प्राप्त करना उतना बुरा नहीं है। आप कुछ पासवर्ड लेने के लिए एक कुंजी व्युत्पत्ति फ़ंक्शन का उपयोग कर सकते हैं और इसे एक बहुत ही सुरक्षित कुंजी बना सकते हैं। आप "पीकेएफडीएफ 2 के साथ कितने पास करते हैं?" जैसे मुद्दों पर चर्चा करते हैं, लेकिन यह एक और विषय है

  1. आदर्श रूप से, आप डिवाइस से एईएस कुंजी को स्टोर करते हैं। आपको सर्वर से कुंजी को सुरक्षित रूप से, मज़बूती से, और सुरक्षित रूप से प्राप्त करने के लिए एक अच्छा तरीका पता लगाना होगा

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

जब आप लॉग इन करते हैं, तो आप स्थानीय लॉगिन पर कुंजी को फिर से प्राप्त करते हैं और इसे संग्रहीत कुंजी से तुलना करते हैं। एक बार जब यह हो जाता है, तो आप एईएस के लिए व्युत्पन्न कुंजी # 2 का उपयोग करते हैं।

  1. "आम तौर पर सुरक्षित" दृष्टिकोण का उपयोग करके, आप एईएस का उपयोग करके डेटा को एन्क्रिप्ट करते हैं और MODE_PRIVATE में कुंजी संग्रहीत करते हैं। यह हाल ही में ish Android ब्लॉग पोस्ट द्वारा अनुशंसित है। अविश्वसनीय रूप से सुरक्षित नहीं है, लेकिन सादे पाठ पर कुछ लोगों के लिए बेहतर है

आप इनमें से बहुत से बदलाव कर सकते हैं। उदाहरण के लिए, एक पूर्ण लॉगिन अनुक्रम के बजाय, आप एक त्वरित पिन (व्युत्पन्न) कर सकते हैं। त्वरित पिन एक पूर्ण लॉगिन अनुक्रम के रूप में सुरक्षित नहीं हो सकता है, लेकिन यह सादे पाठ की तुलना में कई गुना अधिक सुरक्षित है


5

मुझे पता है कि यह थोड़ा सा नेक्रोमेंसी है, लेकिन आपको Android AccountManager का उपयोग करना चाहिए । यह इस परिदृश्य के लिए उद्देश्य से बनाया गया है। यह थोड़ा बोझिल है, लेकिन सिम कार्ड बदलने पर स्थानीय क्रेडेंशियल्स को अमान्य करने वाली चीजों में से एक है, इसलिए यदि कोई आपके फोन को स्वाइप करता है और इसमें एक नया सिम फेंकता है, तो आपकी साख से समझौता नहीं किया जाएगा।

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

SampleSyncAdapter एक उदाहरण है जो संग्रहीत खाता क्रेडेंशियल्स का उपयोग करता है।


1
कृपया ध्यान दें कि खाता प्रबंधक का उपयोग करना ऊपर दिए गए किसी भी अन्य तरीके से अधिक सुरक्षित नहीं है! डेवलपर
.android.com/training/id-auth/…

1
खाता प्रबंधक के लिए उपयोग का मामला तब है जब खाते को अलग-अलग ऐप और विभिन्न लेखकों के ऐप के बीच साझा किया जाना है। पासवर्ड को स्टोर करना और किसी भी अनुरोध करने वाले ऐप को देना उचित नहीं होगा। यदि उपयोगकर्ता / पासवर्ड का उपयोग केवल एक ऐप के लिए है, तो खाता प्रबंधक का उपयोग न करें।
dolmen

1
@ डॉल्मेन, यह बिल्कुल सही नहीं है। खाता प्रबंधक किसी भी ऐप को खाता पासवर्ड नहीं देगा, जिसका UID प्रमाणक से मेल नहीं खाता है। नाम, हाँ; ऑर्टिक टोकन, हाँ; पासवर्ड, नहीं। यदि आप कोशिश करते हैं, तो यह एक SecurityException फेंक देगा। और उपयोग का मामला इससे कहीं अधिक व्यापक है। डेवलपर
जॉन ओ

5

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

जैसे कि दो सुझाव हैं, अगर सुरक्षा आपके लिए एक बड़ी चिंता का विषय है तो मैं इसे बाहर फेंकना चाहूंगा:

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

2) 2 कारक प्रमाणीकरण का उपयोग करें। यह अधिक कष्टप्रद और घुसपैठ हो सकता है लेकिन कुछ अनुपालन स्थितियों के लिए अपरिहार्य है।


2

आप इस छोटे से परिवाद को भी देख सकते हैं, जिसमें आपके द्वारा बताई गई कार्यक्षमता है।

https://github.com/kovmarci86/android-secure-preferences

यह यहां के कुछ अन्य एप्रोच के समान है। आशा है कि मदद करता है :)


2

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

साझा प्राथमिकताएँ कैसे उपयोग करें

उपयोगकर्ता सेटिंग्स आम तौर पर SharedPreferencesएक कुंजी-मूल्य जोड़ी के साथ एंड्रॉइड में स्थानीय रूप से सहेजी जाती हैं । आप Stringसंबंधित मान को सहेजने या देखने के लिए कुंजी का उपयोग करते हैं ।

साझा प्राथमिकताएं लिखें

String key = "myInt";
int valueToSave = 10;

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(key, valueToSave).commit();

तुरंत के बजाय पृष्ठभूमि में बचाने apply()के commit()लिए उपयोग करें ।

साझा प्राथमिकताएं पढ़ें

String key = "myInt";
int defaultValue = 0;

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
int savedValue = sharedPref.getInt(key, defaultValue);

यदि कुंजी नहीं मिली है तो डिफ़ॉल्ट मान का उपयोग किया जाता है।

टिप्पणियाँ

  • स्थानीय कुंजी स्ट्रिंग का उपयोग करने के बजाय, जैसा मैंने ऊपर किया था, कई स्थानों पर एक एकल स्थान में एक निरंतर उपयोग करना बेहतर होगा। आप अपनी सेटिंग गतिविधि के शीर्ष पर कुछ इस तरह का उपयोग कर सकते हैं:

    final static String PREF_MY_INT_KEY = "myInt";
  • मैं एक प्रयोग किया जाता intमेरी उदाहरण में है, लेकिन आप भी उपयोग कर सकते हैं putString(), putBoolean(), getString(), getBoolean(), आदि

  • देखें प्रलेखन अधिक जानकारी के लिए।
  • SharedPreferences प्राप्त करने के कई तरीके हैं। क्या देखना है, इसके लिए यह उत्तर देखें ।

1

यह उत्तर मार्क द्वारा सुझाए गए दृष्टिकोण पर आधारित है। EditTextPreference वर्ग का एक कस्टम संस्करण बनाया गया है जो दृश्य में देखे गए सादे पाठ और वरीयताओं के भंडारण में संग्रहीत पासवर्ड के एक एन्क्रिप्टेड संस्करण के बीच आगे और पीछे धर्मान्तरित होता है।

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

यहाँ कस्टम EditTextPreference वर्ग के लिए कोड है:

package com.Merlinia.OutBack_Client;

import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.util.Base64;

import com.Merlinia.MEncryption_Main.MEncryptionUserPassword;


/**
 * This class extends the EditTextPreference view, providing encryption and decryption services for
 * OutBack user passwords. The passwords in the preferences store are first encrypted using the
 * MEncryption classes and then converted to string using Base64 since the preferences store can not
 * store byte arrays.
 *
 * This is largely copied from this article, except for the encryption/decryption parts:
 * https://groups.google.com/forum/#!topic/android-developers/pMYNEVXMa6M
 */
public class EditPasswordPreference  extends EditTextPreference {

    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context) {
        super(context);
    }


    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
    }


    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context, AttributeSet attributeSet, int defaultStyle) {
        super(context, attributeSet, defaultStyle);
    }


    /**
     * Override the method that gets a preference from the preferences storage, for display by the
     * EditText view. This gets the base64 password, converts it to a byte array, and then decrypts
     * it so it can be displayed in plain text.
     * @return  OutBack user password in plain text
     */
    @Override
    public String getText() {
        String decryptedPassword;

        try {
            decryptedPassword = MEncryptionUserPassword.aesDecrypt(
                     Base64.decode(getSharedPreferences().getString(getKey(), ""), Base64.DEFAULT));
        } catch (Exception e) {
            e.printStackTrace();
            decryptedPassword = "";
        }

        return decryptedPassword;
    }


    /**
     * Override the method that gets a text string from the EditText view and stores the value in
     * the preferences storage. This encrypts the password into a byte array and then encodes that
     * in base64 format.
     * @param passwordText  OutBack user password in plain text
     */
    @Override
    public void setText(String passwordText) {
        byte[] encryptedPassword;

        try {
            encryptedPassword = MEncryptionUserPassword.aesEncrypt(passwordText);
        } catch (Exception e) {
            e.printStackTrace();
            encryptedPassword = new byte[0];
        }

        getSharedPreferences().edit().putString(getKey(),
                                          Base64.encodeToString(encryptedPassword, Base64.DEFAULT))
                .commit();
    }


    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        if (restoreValue)
            getEditText().setText(getText());
        else
            super.onSetInitialValue(restoreValue, defaultValue);
    }
}

यह दिखाता है कि इसका उपयोग कैसे किया जा सकता है - यह "आइटम" फ़ाइल है जो वरीयताओं को प्रदर्शित करती है। ध्यान दें कि इसमें तीन सामान्य EditTextPreference विचार हैं और एक कस्टम EditPasswordPreference विचार हैं।

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <EditTextPreference
        android:key="@string/useraccountname_key"
        android:title="@string/useraccountname_title"
        android:summary="@string/useraccountname_summary"
        android:defaultValue="@string/useraccountname_default"
        />

    <com.Merlinia.OutBack_Client.EditPasswordPreference
        android:key="@string/useraccountpassword_key"
        android:title="@string/useraccountpassword_title"
        android:summary="@string/useraccountpassword_summary"
        android:defaultValue="@string/useraccountpassword_default"
        />

    <EditTextPreference
        android:key="@string/outbackserverip_key"
        android:title="@string/outbackserverip_title"
        android:summary="@string/outbackserverip_summary"
        android:defaultValue="@string/outbackserverip_default"
        />

    <EditTextPreference
        android:key="@string/outbackserverport_key"
        android:title="@string/outbackserverport_title"
        android:summary="@string/outbackserverport_summary"
        android:defaultValue="@string/outbackserverport_default"
        />

</PreferenceScreen>

वास्तविक एन्क्रिप्शन / डिक्रिप्शन के लिए, पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है। मैं वर्तमान में इस लेख के आधार पर कुछ कोड का उपयोग कर रहा हूं http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/ , हालांकि विभिन्न मूल्यों के साथ कुंजी और आरंभीकरण वेक्टर के लिए।


1

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

संवेदनशील डेटा को सुरक्षित रूप से संग्रहीत किया जाना चाहिए या बिल्कुल नहीं। एक खोई हुई डिवाइस या मैलवेयर संक्रमण की स्थिति में असुरक्षित रूप से संग्रहीत डेटा से समझौता किया जा सकता है।


1

मैं ईसीबी मोड में आरएसए का उपयोग करके पासवर्ड को एन्क्रिप्ट करने के लिए एंड्रॉइड कीस्टोर का उपयोग करता हूं और फिर इसे शेयर्डप्रीफेरेंस में सहेजता हूं।

जब मुझे पासवर्ड वापस चाहिए तो मैंने SharedPreferences से एन्क्रिप्टेड को पढ़ा और इसे KeyStore का उपयोग करके डिक्रिप्ट किया।

इस पद्धति से आप एक सार्वजनिक / निजी की-पेयर बनाते हैं, जहाँ निजी रूप से एंड्रॉइड द्वारा सुरक्षित रूप से संग्रहीत और प्रबंधित किया जाता है।

यह कैसे करना है पर एक लिंक है: Android KeyStore ट्यूटोरियल


-2

साझा प्राथमिकताएं हमारे एप्लिकेशन डेटा को संग्रहीत करने का सबसे आसान तरीका है। लेकिन यह संभव है कि कोई भी एप्लिकेशन मैनेजर के माध्यम से हमारे साझा वरीयताओं के डेटा को साफ कर सकता है। मुझे नहीं लगता कि यह हमारे आवेदन के लिए पूरी तरह से सुरक्षित है।


-3

आपको पासवर्ड स्टोर करने के लिए साइक्लाइट, सिक्योरिटी एपिट का उपयोग करना होगा। यहाँ सबसे अच्छा उदाहरण है, जो पासवर्ड स्टोर करता है, - पासवर्ड कैफे। यहाँ स्रोत और स्पष्टीकरण के लिए लिंक है - http://code.google.com/p/android-passwordsafe/


3
ओपी को एक उपयोगकर्ता नाम और पासवर्ड जोड़ी जमा करने की आवश्यकता है। इस एक उपयोग के लिए एक पूरी डेटाबेस तालिका बनाने पर विचार करना हास्यास्पद होगा
HXCaine

@HXCaine मैं सम्मानपूर्वक असहमत हूं - मैं उपयोगकर्ता / पासवर्ड साइक्लाइट टेबल का कम से कम 1 अन्य उपयोग देख सकता हूं। यदि आप जोखिम को स्वीकार करते हैं (sqlite का उपयोग करके) ACCEPTABLE, सरल अनुप्रयोग लॉगिन प्रमाणीकरण के अलावा, आप कई एफ़टीपी पासवर्ड (यदि आपका ऐप एफ़टीपी - मेरा कभी-कभी उपयोग करता है) का संग्रह करने के लिए तालिका का उपयोग कर सकता है, उदाहरण के लिए। इसके अलावा, इस हेरफेर के लिए एक साइक्लाइट एडेप्टर वर्ग बनाना बॉयलरप्लेट सरल है।
टॉनी गिल

दो साल पुरानी टिप्पणी का अच्छा पुनरुत्थान! निष्पक्ष होने के लिए, मेरी टिप्पणी जवाब के एक साल बाद थी :) यहां तक ​​कि एफ़टीपी पासवर्ड के साथ, ओवरहेड एक SQLite तालिका के साथ अंतरिक्ष और कोडिंग दोनों के संदर्भ में SharedPreferences के साथ बहुत बड़ा है। निश्चित रूप से यह आवश्यक नहीं हो सकता है
HXCaine
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.