¿Cuál es la forma más adecuada de almacenar la configuración del usuario en la aplicación de Android

308

Estoy creando una aplicación que se conecta al servidor usando nombre de usuario / contraseña y me gustaría habilitar la opción "Guardar contraseña" para que el usuario no tenga que escribir la contraseña cada vez que se inicia la aplicación.

Intenté hacerlo con Preferencias compartidas, pero no estoy seguro de si esta es la mejor solución.

Agradecería cualquier sugerencia sobre cómo almacenar valores / configuraciones de usuario en la aplicación de Android.

Niko Gamulin
fuente

Respuestas:

233

En general, SharedPreferences es su mejor opción para almacenar preferencias, por lo que, en general, recomendaría ese enfoque para guardar la aplicación y la configuración del usuario.

La única área de preocupación aquí es lo que está ahorrando. Las contraseñas siempre son algo complicado de almacenar, y sería especialmente cuidadoso de almacenarlas como texto sin cifrar. La arquitectura de Android es tal que las Preferencias Compartidas de su aplicación están protegidas para evitar que otras aplicaciones puedan acceder a los valores, por lo que hay algo de seguridad allí, pero el acceso físico a un teléfono podría permitir el acceso a los valores.

Si es posible, consideraría modificar el servidor para usar un token negociado para proporcionar acceso, algo como OAuth . Alternativamente, es posible que necesite construir algún tipo de tienda criptográfica, aunque eso no es trivial. Como mínimo, asegúrese de cifrar la contraseña antes de escribirla en el disco.

Reto Meier
fuente
3
¿Podrías explicar a qué te refieres con sandboxed?
Abhijit
14
Un programa de espacio aislado es cualquier aplicación cuyo proceso e información (como las preferencias compartidas) permanecen ocultos para el resto de las aplicaciones. Una aplicación de Android que se ejecuta en un paquete no puede acceder directamente a nada dentro de otro paquete. Es por eso que las aplicaciones en el mismo paquete (que siempre son suyas) podrían acceder a la información de otros
Korcholis
@Reto Meier mi requisito es proteger los servicios web disponibles públicamente para los que estoy usando un token, ¿es seguro almacenarlo en preferencias compartidas? Tengo un receptor de difusión de arranque en mi aplicación que eliminará todos los datos de preferencias compartidas si encuentra el dispositivo como rooteado. ¿Es esto suficiente para proteger mi ficha?
pyus13
1
De acuerdo con android-developers.blogspot.com/2013/02/… , las credenciales de usuario deben almacenarse con el conjunto de indicadores MODE_PRIVATE y almacenarse en almacenamiento interno (con las mismas advertencias sobre el almacenamiento de cualquier tipo de contraseña localmente abierta para atacar). Dicho esto, ¿usar MODE_PRIVATEcon SharedPreferences equivale a hacer lo mismo con un archivo creado en almacenamiento interno, en términos de efectividad para ofuscar los datos almacenados localmente?
qix
66
No almacene una contraseña en las preferencias compartidas. Si el usuario alguna vez pierde el teléfono, ha perdido la contraseña. Será leido. Si usaron esa contraseña en otro lugar, todos los lugares donde la usaron están comprometidos. Además, ha perdido esta cuenta de forma permanente porque con la contraseña pueden cambiar su contraseña. La forma correcta de hacer esto es enviar la contraseña al servidor una vez y recibir un token de inicio de sesión. Almacene eso en preferencia compartida y envíelo con cada solicitud. Si esa ficha se ve comprometida, no se pierde nada más.
Gabe Sechan
211

Estoy de acuerdo con Reto y fiXedd. Hablando objetivamente, no tiene mucho sentido invertir mucho tiempo y esfuerzo en encriptar las contraseñas en SharedPreferences, ya que es muy probable que cualquier atacante que tenga acceso a su archivo de preferencias también tenga acceso al binario de su aplicación y, por lo tanto, las claves para desencriptar el contraseña.

Sin embargo, dicho esto, parece haber una iniciativa publicitaria que continúa identificando aplicaciones móviles que almacenan sus contraseñas en texto sin cifrar en SharedPreferences y que arrojan luz desfavorable sobre esas aplicaciones. Consulte http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/ y http://viaforensics.com/appwatchdog para ver algunos ejemplos.

Si bien necesitamos que se preste más atención a la seguridad en general, diría que este tipo de atención en este tema en particular no aumenta significativamente nuestra seguridad general. Sin embargo, como las percepciones son como son, aquí hay una solución para cifrar los datos que coloca en SharedPreferences.

Simplemente envuelva su propio objeto SharedPreferences en este, y cualquier dato que lea / escriba se cifrará y descifrará automáticamente. p.ej.

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

Aquí está el código para la clase:

/**
 * 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
fuente
3
FYI Base64 está disponible en API nivel 8 (2.2) y posterior. Puede usar iharder.sourceforge.net/current/java/base64 o algo más para sistemas operativos anteriores.
emmby
34
Sí, escribí esto. Siéntase libre de usar, no se necesita atribución
emmby
8
Estoy de acuerdo contigo. Pero si la contraseña solo se usa en el servidor, ¿por qué no usar el cifrado de clave pública / privada? Clave pública en el cliente al guardar la contraseña. El cliente nunca tendrá que volver a leer la contraseña de texto claro, ¿verdad? El servidor puede descifrarlo con la clave privada. Entonces, incluso si alguien revisa el código fuente de su aplicación, no puede obtener la contraseña, excepto que piratea su servidor y obtiene la clave privada.
Patrick Boos
44
Agregué algunas características a este código y lo coloqué en github en github.com/RightHandedMonkey/WorxForUs_Library/blob/master/src/… . Ahora maneja la migración de preferencias no encriptadas a la encriptada. También genera la clave en tiempo de ejecución, por lo que descompilar la aplicación no libera la clave.
RightHandedMonkey
3
Adición tardía, pero el comentario de @PatrickBoos es una gran idea. Sin embargo, un problema con esto es que, aunque haya cifrado la contraseña, un atacante que robó ese cifrado aún podría iniciar sesión en sus servidores, porque estos descifran. Una adición a este enfoque es cifrar la contraseña junto con una marca de tiempo. De esa manera, puede decidir, por ejemplo, permitir solo las contraseñas guardadas en el pasado reciente (como agregar una fecha de vencimiento a su "token"), o incluso requerir que ciertos usuarios tengan una marca de tiempo desde una fecha en particular ("revoquemos" viejos "tokens").
adevine
29

La forma más sencilla de almacenar una preferencia única en una actividad de Android es hacer algo como esto:

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

Si le preocupa la seguridad de estos, siempre puede cifrar la contraseña antes de almacenarla.

Jeremy Logan
fuente
99
No podría estar más de acuerdo con usted acerca de este enfoque simplista; Sin embargo, ¿siempre debe preocuparse por la seguridad de las contraseñas que almacena? Dependiendo de su aplicación, tiene posibles responsabilidades por la información personal robada. Solo señalar esto a cualquiera que intente almacenar contraseñas reales para cosas como cuentas bancarias o algo igualmente importante. Aunque todavía te voto.
While-E
1
¿Dónde guardarías la clave que almacenó la contraseña? Si las preferencias compartidas son accesibles por otros usuarios, también lo es la clave.
OrhanC1
@ OrhanC1 ¿recibió la respuesta?
eRaisedToX
10

Con el fragmento proporcionado por Richard, puede cifrar la contraseña antes de guardarla. Sin embargo, la API de preferencias no proporciona una manera fácil de interceptar el valor y cifrarlo: puede bloquearlo para que se guarde a través de un escucha OnPreferenceChange, y en teoría podría modificarlo a través de un preferenciasChangeListener, pero eso da como resultado un bucle sin fin.

Anteriormente había sugerido agregar una preferencia "oculta" para lograr esto. Definitivamente no es la mejor manera. Voy a presentar otras dos opciones que considero más viables.

Primero, el más simple, está en un PreferChangeListener, puede tomar el valor ingresado, cifrarlo y luego guardarlo en un archivo de preferencias alternativo:

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

La segunda forma, y ​​la forma en que ahora prefiero, es crear su propia preferencia personalizada, extendiendo EditTextPreference, @ Override'ing setText()y los getText()métodos, de modo que setText()cifre la contraseña y getText()devuelva nulo.

marca
fuente
Sé que esto es bastante antiguo, pero ¿le importaría publicar su código para su versión personalizada de EditTextPreference, por favor?
RenniePet
No importa, encontré una muestra utilizable aquí groups.google.com/forum/#!topic/android-developers/pMYNEVXMa6M y lo tengo funcionando ahora. Gracias por sugerir este enfoque.
RenniePet
6

Bueno; Ha pasado un tiempo desde que la respuesta es un poco mixta, pero aquí hay algunas respuestas comunes. Investigué esto como loco y fue difícil construir una buena respuesta

  1. El método MODE_PRIVATE se considera generalmente seguro, si supone que el usuario no ha rooteado el dispositivo. Sus datos se almacenan en texto plano en una parte del sistema de archivos a la que solo puede acceder el programa original. Esto hace que sea fácil obtener la contraseña con otra aplicación en un dispositivo rooteado. Por otra parte, ¿quieres soportar dispositivos rooteados?

  2. AES sigue siendo el mejor cifrado que puede hacer. Recuerde buscar esto si está comenzando una nueva implementación si ha pasado un tiempo desde que publiqué esto. El mayor problema con esto es "¿Qué hacer con la clave de cifrado?"

Entonces, ahora estamos en "¿Qué hacer con la llave?" parte. Esta es la parte difícil. Obtener la llave no es tan malo. Puede usar una función de derivación de clave para tomar alguna contraseña y convertirla en una clave bastante segura. Tienes problemas como "¿cuántos pases haces con PKFDF2?", Pero ese es otro tema

  1. Idealmente, almacena la clave AES fuera del dispositivo. Sin embargo, debe encontrar una buena manera de recuperar la clave del servidor de forma segura y confiable

  2. Tiene una secuencia de inicio de sesión de algún tipo (incluso la secuencia de inicio de sesión original que tiene para el acceso remoto). Puede hacer dos ejecuciones de su generador de claves con la misma contraseña. Cómo funciona esto es que deriva la clave dos veces con una nueva sal y un nuevo vector de inicialización segura. Usted almacena una de esas contraseñas generadas en el dispositivo y usa la segunda contraseña como clave AES.

Cuando inicia sesión, deriva la clave en el inicio de sesión local y la compara con la clave almacenada. Una vez hecho esto, usa la clave de derivación # 2 para AES.

  1. Usando el enfoque "generalmente seguro", usted cifra los datos usando AES y almacena la clave en MODE_PRIVATE. Esto es recomendado por una publicación reciente en el blog de Android. No es increíblemente seguro, pero es mucho mejor para algunas personas con texto sin formato

Puedes hacer muchas variaciones de estos. Por ejemplo, en lugar de una secuencia de inicio de sesión completa, puede hacer un PIN rápido (derivado). El PIN rápido puede no ser tan seguro como una secuencia de inicio de sesión completa, pero es muchas veces más seguro que el texto sin formato

Joe Plante
fuente
5

Sé que esto es un poco de nigromancia, pero debes usar el Android AccountManager . Está especialmente diseñado para este escenario. Es un poco engorroso, pero una de las cosas que hace es invalidar las credenciales locales si la tarjeta SIM cambia, por lo que si alguien desliza su teléfono y arroja una nueva SIM, sus credenciales no se verán comprometidas.

Esto también le brinda al usuario una forma rápida y fácil de acceder (y potencialmente eliminar) las credenciales almacenadas para cualquier cuenta que tengan en el dispositivo, todo desde un solo lugar.

SampleSyncAdapter es un ejemplo que utiliza las credenciales de la cuenta almacenada.

Jon O
fuente
1
¡Tenga en cuenta que usar AccountManager no es más seguro que cualquier otro método proporcionado anteriormente! developer.android.com/training/id-auth/…
Sander Versluys el
1
El caso de uso de AccountManager es cuando la cuenta debe compartirse entre diferentes aplicaciones y aplicaciones de diferentes autores. No sería apropiado almacenar la contraseña y dársela a cualquier aplicación solicitante. Si el uso del usuario / contraseña es solo para una sola aplicación, no use AccountManager.
dolmen
1
@dolmen, eso no es del todo correcto. El AccountManager no dará la contraseña de la cuenta a ninguna aplicación cuyo UID no coincida con el del Autenticador. El nombre si; el token de autenticación, sí; la contraseña no. Si lo intentas, arrojará una SecurityException. Y el caso de uso es mucho más amplio que eso. developer.android.com/training/id-auth/identify.html
Jon O
5

Lanzaré mi sombrero al ring solo para hablar sobre la seguridad de las contraseñas en general en Android. En Android, el dispositivo binario debe considerarse comprometido; esto es lo mismo para cualquier aplicación final que esté bajo el control directo del usuario. Conceptualmente, un hacker podría usar el acceso necesario al binario para descompilarlo y eliminar sus contraseñas cifradas, etc.

Como tal, hay dos sugerencias que me gustaría lanzar si la seguridad es una preocupación importante para usted:

1) No almacene la contraseña real. Almacene un token de acceso otorgado y use el token de acceso y la firma del teléfono para autenticar la sesión del lado del servidor. El beneficio de esto es que puede hacer que el token tenga una duración limitada, no está comprometiendo la contraseña original y tiene una buena firma que puede usar para correlacionar el tráfico más tarde (por ejemplo, para verificar intentos de intrusión e invalidar el token que lo hace inútil).

2) Utilice la autenticación de 2 factores. Esto puede ser más molesto e intrusivo, pero para algunas situaciones de cumplimiento inevitable.

dcgregorya
fuente
2

Esta es una respuesta complementaria para aquellos que llegan aquí según el título de la pregunta (como lo hice) y no necesitan lidiar con los problemas de seguridad relacionados con el almacenamiento de contraseñas.

Cómo usar las preferencias compartidas

La configuración del usuario generalmente se guarda localmente en Android usando SharedPreferencesun par clave-valor. Usas elString tecla para guardar o buscar el valor asociado.

Escribir en preferencias compartidas

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

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

Usar en apply()lugar decommit() guardar en segundo plano en lugar de inmediatamente.

Leer desde preferencias compartidas

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

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

El valor predeterminado se usa si no se encuentra la clave.

Notas

  • En lugar de usar una cadena de clave local en varios lugares como lo hice anteriormente, sería mejor usar una constante en una sola ubicación. Podría usar algo como esto en la parte superior de su actividad de configuración:

      final static String PREF_MY_INT_KEY = "myInt";
  • He utilizado una inten mi ejemplo, pero también se puede utilizar putString(), putBoolean(), getString(), getBoolean(), etc.

  • Consulte la documentación para más detalles.

  • Hay varias formas de obtener SharedPreferences. Vea esta respuesta para saber qué buscar.

Suragch
fuente
1

Esta respuesta se basa en un enfoque sugerido por Mark. Se crea una versión personalizada de la clase EditTextPreference que convierte de ida y vuelta entre el texto sin formato que se ve en la vista y una versión cifrada de la contraseña almacenada en el almacenamiento de preferencias.

Como se ha señalado por la mayoría de los que respondieron en este hilo, esta no es una técnica muy segura, aunque el grado de seguridad depende en parte del código de cifrado / descifrado utilizado. Pero es bastante simple y conveniente, y frustrará la mayoría de los espías casuales.

Aquí está el código para la clase personalizada 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);
    }
}

Esto muestra cómo se puede usar: este es el archivo de "elementos" que controla la pantalla de preferencias. Tenga en cuenta que contiene tres vistas normales de EditTextPreference y una de las vistas personalizadas 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>

En cuanto al cifrado / descifrado real, eso se deja como ejercicio para el lector. Actualmente estoy usando algún código basado en este artículo http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/ , aunque con valores diferentes para la clave y el vector de inicialización.

RenniePet
fuente
1

En primer lugar, creo que los datos del usuario no deben almacenarse en el teléfono, y si es necesario almacenar datos en algún lugar del teléfono, deben cifrarse con los datos privados de las aplicaciones. La seguridad de las credenciales de los usuarios debe ser la prioridad de la aplicación.

Los datos confidenciales deben almacenarse de forma segura o no almacenarse. En caso de pérdida de dispositivo o infección de malware, los datos almacenados de forma insegura pueden verse comprometidos.

Yauraw Gadav
fuente
1

Uso Android KeyStore para cifrar la contraseña usando RSA en modo ECB y luego guardarla en SharedPreferences.

Cuando quiero recuperar la contraseña, leo la encriptada de SharedPreferences y la descifro usando KeyStore.

Con este método, genera un par de claves público / privado donde el privado se almacena y administra con seguridad en Android.

Aquí hay un enlace sobre cómo hacer esto: Tutorial de Android KeyStore

Braveblacklion
fuente
-2

Las preferencias compartidas son la forma más fácil de almacenar los datos de nuestra aplicación. pero es posible que cualquiera pueda borrar nuestros datos de preferencias compartidas a través del administrador de aplicaciones. Por lo tanto, no creo que sea completamente seguro para nuestra aplicación.

Rohit Jain
fuente
-3

necesita usar el sqlite, apit de seguridad para almacenar las contraseñas. este es el mejor ejemplo, que almacena contraseñas, - passwordsafe. Aquí hay un enlace para la fuente y la explicación: http://code.google.com/p/android-passwordsafe/

Artem Russakovskii
fuente
3
El OP necesita almacenar un par de nombre de usuario y contraseña. Sería ridículo considerar crear una tabla de base de datos completa para este único uso
HXCaine,
@HXCaine estoy respetuosamente en desacuerdo: puedo ver al menos otro uso de una tabla sqlite de usuario / contraseñas. SI USTED CONSIDERA QUE EL RIESGO (de usar sqlite) ES ACEPTABLE, además de la simple autenticación de inicio de sesión de la aplicación, puede usar la tabla para almacenar múltiples contraseñas ftp (si su aplicación usa ftp - la mía lo hace a veces), por ejemplo. Además, crear una clase de adaptador sqlite para esta manipulación es simple.
tony gil
¡Bonita resurrección de un comentario de dos años! Para ser justos, mi comentario fue un año después de la respuesta :) Incluso con un puñado de contraseñas FTP, la sobrecarga es mucho mayor con una tabla SQLite que con SharedPreferences tanto en términos de espacio como de codificación. Seguramente eso no puede ser necesario
HXCaine