Каков наиболее подходящий способ хранения пользовательских настроек в приложении Android

308

Я создаю приложение, которое подключается к серверу, используя имя пользователя / пароль, и я хотел бы включить опцию «Сохранить пароль», чтобы пользователю не приходилось вводить пароль при каждом запуске приложения.

Я пытался сделать это с помощью общих настроек, но не уверен, что это лучшее решение.

Буду признателен за любые предложения о том, как хранить пользовательские значения / настройки в приложении Android.

Нико Гамулин
источник

Ответы:

233

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

Единственная проблемная область - это то, что вы экономите. Пароли всегда сложнее хранить, и я бы особенно остерегался хранить их в виде открытого текста. Архитектура Android такова, что SharedPreferences вашего приложения находятся в «песочнице», чтобы другие приложения не могли получить доступ к значениям, поэтому существует некоторая безопасность, но физический доступ к телефону потенциально может предоставить доступ к значениям.

Если возможно, я бы хотел изменить сервер для использования согласованного токена для предоставления доступа, что-то вроде OAuth . В качестве альтернативы вам может понадобиться создать своего рода криптографическое хранилище, хотя это нетривиально. По крайней мере, убедитесь, что вы шифруете пароль перед записью его на диск.

Рето Мейер
источник
3
Не могли бы вы объяснить, что вы подразумеваете под песочницей?
Абхиджит
14
«песочница» - это любое приложение, процесс и информация которого (например, общие параметры) остаются скрытыми от остальных приложений. Android-приложение, работающее в пакете, не может напрямую получить доступ к чему-либо внутри другого пакета. Вот почему приложения в одном пакете (которые всегда ваши) могут получить доступ к информации из других приложений
Корчолис,
@ Reto Meier Мое требование - защищать общедоступные веб-службы, для которых я использую токен, безопасно ли хранить его в общих настройках? в моем приложении есть загрузочный широковещательный приемник, который удалит все данные sharedpreferences, если он обнаружит устройство как рутированное. Этого достаточно, чтобы защитить мой токен.
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);
        }
    }

}
emmby
источник
3
FYI Base64 доступен на уровне API 8 (2.2) и выше. Вы можете использовать iharder.sourceforge.net/current/java/base64 или что-то еще для более ранних ОС.
Эмбби
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
Я не мог согласиться с вами больше об этом упрощенном подходе; Тем не менее, вы всегда должны беспокоиться о безопасности паролей, которые вы храните? В зависимости от вашего заявления, у вас есть потенциальная ответственность за кражу личной информации. Просто указав на это для тех, кто пытается хранить реальные пароли к таким вещам, как банковские счета или что-то такое же важное. Я все еще голосую за тебя.
Пока-E
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()and getText(), чтобы setText()зашифровывать пароль и getText()возвращать ноль.

отметка
источник
Я знаю, что это довольно старая версия, но не могли бы вы опубликовать свой код для пользовательской версии EditTextPreference, пожалуйста?
RenniePet
Не берите в голову, я нашел пригодный для использования образец здесь 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/…
Сандер Верслуйс
1
Вариант использования AccountManager - это когда учетная запись должна использоваться несколькими приложениями и приложениями разных авторов. Хранение пароля и передача его любому запрашивающему приложению нецелесообразно. Если использование пользователя / пароля только для одного приложения, не используйте AccountManager.
Дольмен
1
@ dolmen, это не совсем правильно. AccountManager не будет передавать пароль учетной записи любому приложению, UID которого не совпадает с идентификатором аутентификатора. Название, да; аутентификационный токен, да; пароль нет. Если вы попытаетесь, это вызовет исключение SecurityException. И вариант использования гораздо шире, чем это. developer.android.com/training/id-auth/identify.html
Jon O
5

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

Таким образом, есть два предложения, которые я хотел бы высказать, если безопасность является серьезной проблемой для вас:

1) Не храните действительный пароль. Сохраните предоставленный токен доступа и используйте токен доступа и подпись телефона для аутентификации сеанса на стороне сервера. Преимущество этого состоит в том, что вы можете сделать токен ограниченным по продолжительности, вы не ставите под угрозу исходный пароль, и у вас есть хорошая подпись, которую вы можете использовать для корреляции с трафиком позже (например, для проверки попыток вторжения и аннулирования токен делает его бесполезным).

2) Использовать двухфакторную аутентификацию. Это может быть более раздражающим и навязчивым, но для некоторых случаев соблюдения требований неизбежно.

dcgregorya
источник
2

Вы также можете проверить эту маленькую библиотеку, содержащую упомянутую вами функциональность.

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

Это похоже на некоторые другие подходы здесь. Надеюсь помогает :)

Marcell
источник
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. Посмотрите этот ответ для того, что посмотреть.

Suragch
источник
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/ , хотя и с другими значениями для ключа и вектора инициализации.

RenniePet
источник
1

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

Чувствительные данные должны храниться надежно или не храниться вообще. В случае утери устройства или заражения вредоносным ПО данные, хранящиеся небезопасно, могут быть скомпрометированы.

Яурав Гадав
источник
1

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

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

С помощью этого метода вы генерируете открытую / закрытую пару ключей, где частная надежно хранится и управляется Android.

Вот ссылка о том, как это сделать: Android KeyStore Tutorial

Braveblacklion
источник
-2

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

Рохит Джайн
источник
-3

вам нужно использовать sqlite, apit безопасности для хранения паролей. Вот лучший пример, который хранит пароли, - Passwordsafe. вот ссылка на источник и объяснение - http://code.google.com/p/android-passwordsafe/

Артем Руссаковский
источник
3
ОП должен хранить одну пару имени пользователя и пароля. Было бы смешно подумать о создании всей таблицы базы данных для этого одного использования
HXCaine
@HXCaine Я с уважением не согласен - я вижу по крайней мере 1 другое использование таблицы sqlite пользователя / паролей. ЕСЛИ ВЫ СЧИТАЕТЕ РИСК (от использования sqlite), ПРИНИМАЕТСЯ, помимо простой аутентификации входа в систему приложения, вы можете использовать таблицу, например, для хранения нескольких паролей ftp (если ваше приложение иногда использует ftp - mine do). Кроме того, создание класса адаптера sqlite для этой манипуляции очень просто.
Тони Джил
Хорошее воскресение двухлетнего комментария! Честно говоря, мой комментарий был через год после ответа :) Даже с небольшим количеством паролей FTP, издержки намного больше с таблицей SQLite, чем с SharedPreferences, как с точки зрения пространства и кодирования. Конечно, это не может быть необходимым
HXCaine