Що є найбільш підходящим способом зберігання налаштувань користувачів у додатку Android


308

Я створюю програму, яка підключається до сервера за допомогою імені користувача / пароля, і я хотів би включити опцію "Зберегти пароль", щоб користувачеві не потрібно було вводити пароль під час кожного запуску програми.

Я намагався зробити це із спільними налаштуваннями, але не впевнений, чи це найкраще рішення.

Буду вдячний за будь-яку пропозицію щодо збереження цінностей / налаштувань користувачів у додатку Android.

Відповіді:


233

Загалом, SharedPreferences - це найкраща пропозиція для зберігання налаштувань, тому загалом я рекомендую такий підхід для збереження налаштувань програми та користувачів.

Єдиною проблемою тут є те, що ви економите. Паролі завжди є складною справою, і я б особливо обережно зберігав їх як чіткий текст. Архітектура Android така, що SharedPreferences вашої програми перебуває в пісочному режимі, щоб інші програми не могли отримати доступ до значень, тому там є деяка безпека, але фізичний доступ до телефону може потенційно дозволити доступ до значень.

Якщо можливо, я б міг змінити сервер для використання узгодженого маркера для надання доступу, щось на зразок OAuth . Крім того, вам може знадобитися побудувати якийсь криптографічний магазин, хоча це нетривіально. Принаймні, переконайтеся, що ви шифруєте пароль, перш ніж записати його на диск.


3
Чи можете ви поясніть, що ви маєте на увазі під пісочницею?
Abhijit

14
програма з пісочницею - це будь-яка програма, процес та інформація (як-от ті загальні налаштування) залишаються прихованими від решти програм. Програма для Android, що працює в пакеті, не може безпосередньо отримати доступ до будь-якого іншого пакету. Ось чому програми в тому ж пакеті (який завжди є вашим) могли отримати доступ до інформації з інших
Korcholis

@Reto Meier моя вимога - захищати загальнодоступні веб-сервіси, для яких я використовую маркер, чи зберігає його на спільних налаштуваннях? У моїй програмі є приймач завантажувального завантаження, який видалить усі дані спільних налаштувань, якщо знайдеться пристрій як укорінене. Чи достатньо цього, щоб захистити мій маркер.
pyus13

1
Згідно з android-developers.blogspot.com/2013/02/… , облікові дані користувачів повинні зберігатися з набором прапора MODE_PRIVATE та зберігатися у внутрішньому сховищі (з тими ж застереженнями щодо зберігання будь-якого пароля, локально в кінцевому рахунку, відкритого для атаки). MODE_PRIVATEЗ огляду на це, використання SharedPreferences еквівалентно тому, що робити те ж саме з файлом, створеним на внутрішній сховищі, з точки зору ефективності придушення локально збережених даних?
qix

6
Не зберігайте пароль у спільних налаштуваннях. Якщо користувач коли-небудь втрачає телефон, він втратив пароль. Буде прочитано. Якщо вони використовували цей пароль в іншому місці, кожен раз, коли вони використовували його, ставиться під загрозу. Крім того, ви назавжди втратили цей рахунок, оскільки за допомогою пароля вони можуть змінити ваш пароль. Правильний спосіб зробити це - надіслати пароль до сервера один раз і отримати маркер входу назад. Зберігайте це у спільних налаштуваннях та надсилайте їх із кожним запитом. Якщо цей маркер зіпсований, більше нічого не втрачається.
Габе Сечан

211

Я згоден з Reto та fiXedd. Об'єктивно кажучи, не має великого сенсу вкладати значні час і зусилля в шифрування паролів у SharedPreferences, оскільки будь-який зловмисник, який має доступ до файлу ваших налаштувань, цілком ймовірно, також матиме доступ до бінарного файлу вашої програми, а тому ключі для розшифровки. пароль.

Однак, маючи на увазі, схоже, існує ініціатива рекламної діяльності щодо визначення мобільних додатків, які зберігають свої паролі в чіткому тексті у SharedPreferences та світять несприятливе світло для цих додатків. Дивіться http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/ та http://viaforensics.com/appwatchdog для деяких прикладів.

Хоча нам потрібно більше уваги приділяти безпеці в цілому, я заперечую, що така увага до цього конкретного питання насправді не суттєво підвищує нашу загальну безпеку. Однак, сприймаючи їх такими, якими вони є, ось рішення для шифрування даних, які ви розміщуєте в SharedPreferences.

Просто загорніть у цей власний об’єкт 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 доступний на рівні 8 (2.2) API та новіших версій. Ви можете використовувати iharder.sourceforge.net/current/java/base64 або щось інше для попередніх ОС.
emmby

34
Так, я це написав. Ви можете користуватися, атрибуція не потрібна
emmby

8
Я погоджуюсь з тобою. Але якщо пароль використовується лише на сервері, чому б не використовувати шифрування публічного / приватного ключа? Відкритий ключ клієнта під час збереження пароля. Клієнту більше ніколи не доведеться читати чіткий текстовий пароль, правда? Потім сервер може розшифрувати його за допомогою приватного ключа. Тож навіть якщо хтось проходить ваш вихідний код програми, він не може отримати пароль, за винятком того, що він зламає ваш сервер і отримає приватний ключ.
Патрік Боос

4
До цього коду я додав кілька функцій і розмістив його на github на веб- сайті github.com/RightHandedMonkey/WorxForUs_Library/blob/master/src/… . Тепер він обробляє міграцію незашифрованих налаштувань на зашифровані. Крім того, він генерує ключ під час виконання, тому при розпаді програми не випускається ключ.
RightHandedMonkey

3
Пізнє додавання, але коментар @PatrickBoos - чудова ідея. Одна з проблем з цим полягає в тому, що, хоча ви зашифрували пароль, зловмисник, який викрав цей шифр, все одно зможе увійти на ваші сервери, оскільки ваші сервери роблять розшифровку. Одним із доповнень цього підходу є шифрування пароля разом із часовою позначкою. Таким чином, ви можете вирішити, наприклад, дозволити лише паролі, збережені в недавньому минулому (наприклад, додати дату закінчення терміну дії до вашого "маркера") або навіть вимагати від певних користувачів позначки часу з моменту конкретної дати (давайте вам "скасувати" старі "жетони").
adevine

29

Про найпростіший спосіб збереження єдиного параметра в Android Activity - це зробити щось подібне:

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

Якщо ви переживаєте за безпеку цих даних, ви завжди можете зашифрувати пароль перед його збереженням.


9
Я не міг більше погодитися з вами щодо цього спрощеного підходу; однак, ви завжди повинні турбуватися про безпеку паролів, які ви зберігаєте? Залежно від вашої заяви, у вас є потенційні зобов’язання за викрадену особисту інформацію. Просто вказавши на це для тих, хто намагається зберігати фактичні паролі до таких речей, як банківські рахунки чи щось не менш важливе. Я все ще голосую за тебе.
Хоча-Е

1
Де б ви зберігали ключ, який зберігав пароль? Якщо спільні налаштування доступні для інших користувачів, це є ключовим.
OrhanC1

@ OrhanC1 ти отримав відповідь.?
eRaisedToX

10

Використовуючи фрагмент, наданий Річардом, ви можете зашифрувати пароль перед збереженням. API налаштувань, однак, не забезпечує простий спосіб перехопити значення та зашифрувати його - ви можете заблокувати його збереження за допомогою слухача OnPreferenceChange, і ви теоретично можете змінити його через preferenceChangeListener, але це призводить до нескінченного циклу.

Раніше я пропонував додати "приховану" перевагу, щоб досягти цього. Це, безумовно, не найкращий спосіб. Я збираюся представити два інші варіанти, які я вважаю більш життєздатними.

По-перше, найпростіший - у preferenceChangeListener, ви можете захопити введене значення, зашифрувати його, а потім зберегти його у файлі альтернативних налаштувань:

  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, @ Override'ing setText()та getText()методи, щоб setText()шифрувати пароль і getText()повертати null.


Я знаю, що це досить старе, але ви не хочете розмістити свій код для своєї власної версії EditTextPreference, будь ласка?
РенніПет

Неважливо, я знайшов зразок, який можна використати тут groups.google.com/forum/#!topic/android-developers/pMYNEVXMa6M, і я працюю зараз. Дякуємо, що запропонували такий підхід.
RenniePet

6

Добре; минув час, оскільки відповідь начебто неоднозначна, але ось кілька поширених відповідей. Я це досліджував як божевільний, і важко було скласти хорошу відповідь

  1. Метод MODE_PRIVATE вважається загальнобезпечним, якщо припустити, що користувач не викорінив пристрій. Ваші дані зберігаються у простому тексті в частині файлової системи, доступ до якої може отримати лише оригінальна програма. Це полегшує захоплення пароля іншим додатком на вкоріненому пристрої. Потім знову, чи хочете ви підтримувати вкорінені пристрої?

  2. AES - це все-таки найкраще шифрування, яке ви можете зробити. Не забудьте переглянути це, якщо ви починаєте нову реалізацію, якщо минув час, коли я опублікував це. Найбільша проблема з цим - "Що робити з ключем шифрування?"

Отже, зараз ми перебуваємо у справі "Що робити з ключем?" порція. Це важка частина. Отримати ключ виявляється не так вже й погано. Ви можете скористатися функцією виведення ключа, щоб взяти якийсь пароль і зробити його досить захищеним ключем. Ви все одно стикаєтеся з такими питаннями, як "скільки пропусків ви робите з PKFDF2?", Але це інша тема

  1. В ідеалі ви зберігаєте ключ AES від пристрою. Ви повинні знайти хороший спосіб отримати ключ із сервера надійно, надійно та надійно, хоча

  2. У вас є певна послідовність входу (навіть оригінальна послідовність входу, яку ви робите для віддаленого доступу). Ви можете виконати два запуски генератора ключів на одному паролі. Як це працює, ви отримуєте ключ двічі з новою сіллю та новим захищеним вектором ініціалізації. Ви зберігаєте один із створених паролів на пристрої, а другий пароль використовуєте як ключ AES.

Коли ви входите в систему, ви знову отримуєте ключ на локальному вході та порівнюєте його із збереженим ключем. Як тільки це буде зроблено, ви використовуєте ключ виводу №2 для AES.

  1. Використовуючи підхід "загальнобезпечний", ви шифруєте дані за допомогою AES і зберігаєте ключ у MODE_PRIVATE. Це рекомендує нещодавнє повідомлення в блозі Android. Не неймовірно безпечно, але краще для деяких людей за допомогою простого тексту

Можна зробити безліч варіацій. Наприклад, замість повної послідовності входу можна зробити швидкий PIN-код (похідний). Швидкий PIN-код може бути не настільки безпечним, як повна послідовність входу, але в багато разів безпечніший, ніж звичайний текст


5

Я знаю, що це трохи некромантія, але ви повинні використовувати Android AccountManager . Це створено для цього сценарію. Це трохи громіздко, але однією з речей є недійсність локальних даних, якщо SIM-карта зміниться, тому якщо хтось проведе ваш телефон і кине в нього нову SIM-картку, ваші облікові дані не будуть порушені.

Це також дає користувачеві швидкий і простий спосіб отримати доступ (і, можливо, видалити) збережені облікові дані для будь-якого облікового запису, який вони мають на пристрої, все з одного місця.

SampleSyncAdapter - приклад, який використовує збережені облікові дані облікових записів.


1
Зауважте, що використання AccountManager не є більш безпечним, ніж будь-який інший метод, передбачений вище! developer.android.com/training/id-auth/…
Sander Versluys

1
Випадок використання для AccountManager полягає в тому, коли обліковий запис потрібно ділити між різними програмами та програмами різних авторів. Збереження пароля та надання його будь-якій програмі-запиту не було б доречним. Якщо використання користувача / пароля використовується лише для однієї програми, не використовуйте AccountManager.
долмен

1
@dolmen, це не зовсім правильно. AccountManager не надасть пароль облікового запису жодному додатку, чий UID не відповідає автентифікатору. Ім'я, так; авторський жетон, так; пароль, ні. Якщо ви спробуєте, він кине SecurityException. І випадок використання набагато ширший за це. developer.android.com/training/id-auth/identify.html
Jon O

5

Я кину шапку на ринг просто, щоб поговорити про безпеку паролів взагалі на Android. На Android слід вважати, що двійковий пристрій вважається компрометованим - це те саме для будь-якого кінцевого додатка, який знаходиться під безпосереднім контролем користувача. Концептуально хакер може використовувати необхідний доступ до двійкового файлу, щоб декомпілювати його та викорінювати ваші зашифровані паролі тощо.

Отож, я хочу викинути дві пропозиції, якщо безпека для вас головна проблема:

1) Не зберігайте фактичний пароль. Зберігайте наданий маркер доступу та використовуйте маркер доступу та підпис телефону для аутентифікації на сервері сеансу. Користь для цього полягає в тому, що ви можете зробити маркер обмеженим часом, ви не ставите під загрозу вихідний пароль, і у вас є хороша підпис, яку ви можете використати для співвіднесення трафіку пізніше (наприклад, перевірити наявність спроб вторгнення та визнати недійсним токен робить його марним).

2) Використовуйте 2-факторну аутентифікацію. Це може бути більш дратівливим і настирливим, але для деяких ситуацій дотримання неминуче.



2

Це додаткова відповідь для тих, хто приїжджає сюди, на основі назви питання (як я), і не потрібно мати справу з питаннями безпеки, пов'язаними із збереженням паролів.

Як користуватися загальними налаштуваннями

Налаштування користувачів, як правило, зберігаються локально в Android за 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);

Значення за замовчуванням використовується, якщо ключ не знайдено.

Примітки

  • Замість того, щоб використовувати локальний ключ String у кількох місцях, як я робив вище, було б краще використовувати константу в одному місці. Ви можете використовувати щось подібне у верхній частині вашої діяльності з налаштуваннями:

    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);
    }
}

Це показує, як його можна використовувати - це файл "items", який керує відображенням налаштувань. Зверніть увагу, що він містить три звичайних подання 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

Я використовую Android KeyStore для шифрування пароля за допомогою RSA в режимі ECB, а потім зберігаю його в SharedPreferences.

Коли я хочу повернути пароль, я прочитав зашифрований з SharedPreferences і розшифрував його за допомогою KeyStore.

За допомогою цього методу ви створюєте публічну / приватну пару ключів, де приватна безпечно зберігається та керується Android.

Ось посилання про те, як це зробити: Android KeyStore Tutorial


-2

спільні налаштування - це найпростіший спосіб зберігати наші програми. але можливо, хтось може видалити наші спільні налаштування даних через менеджер додатків. тому я не думаю, що це абсолютно безпечно для нашого додатку.


-3

вам потрібно використовувати sqlite, apit безпеки для зберігання паролів. ось найкращий приклад, який зберігає паролі, - безпечний пароль. ось посилання на джерело та пояснення - http://code.google.com/p/android-passwordsafe/


3
ОП потребує збереження однієї пари імені користувача та пароля. Було б смішно розглянути можливість створення цілої таблиці баз даних для цього одного використання
HXCaine

@HXCaine я з повагою не погоджуюся - я можу побачити щонайменше 1 використання таблиці sqlite користувача / паролів. ЯКЩО ВИ Вважаєте, РИЗИК (з використанням sqlite) ПРИЙМУТИ, окрім простої автентифікації для входу в додаток, ви можете використовувати таблицю для зберігання декількох паролів ftp (якщо ваша програма використовує ftp - моє робити іноді). Плюс до цього, створити клас адаптерів sqlite для цієї маніпуляції - це проста плита.
tony gil

Приємного воскресіння дворічного коментаря! Чесно кажучи, мій коментар був через рік після відповіді :) Навіть за допомогою декількох паролів FTP, накладні витрати набагато більше, ніж із таблицею SQLite, ніж із SharedPreferences як щодо простору, так і для кодування. Звичайно, це не може бути необхідним
HXCaine
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.