Qual è il modo più appropriato per memorizzare le impostazioni utente nell'applicazione Android


308

Sto creando un'applicazione che si collega al server usando username / password e vorrei abilitare l'opzione "Salva password" in modo che l'utente non debba digitare la password ogni volta che si avvia l'applicazione.

Stavo cercando di farlo con le preferenze condivise ma non sono sicuro che questa sia la soluzione migliore.

Gradirei qualsiasi suggerimento su come memorizzare i valori / le impostazioni dell'utente nell'applicazione Android.

Risposte:


233

In generale, le preferenze condivise sono la soluzione migliore per la memorizzazione delle preferenze, quindi in generale consiglierei questo approccio per salvare le impostazioni dell'applicazione e dell'utente.

L'unica area di preoccupazione qui è ciò che stai salvando. Le password sono sempre difficili da archiviare e sarei particolarmente attento a memorizzarle come testo chiaro. L'architettura Android è tale che le SharedPreferences della tua applicazione sono in modalità sandbox per impedire ad altre applicazioni di accedere ai valori, quindi c'è un po 'di sicurezza lì, ma l'accesso fisico a un telefono potrebbe potenzialmente consentire l'accesso ai valori.

Se possibile, prenderei in considerazione la modifica del server per utilizzare un token negoziato per fornire l'accesso, qualcosa come OAuth . In alternativa potrebbe essere necessario costruire una sorta di archivio crittografico, anche se non banale. Per lo meno, assicurati di crittografare la password prima di scriverla sul disco.


3
Potresti spiegare cosa intendi per sandbox?
Abhijit,

14
un programma sandbox è qualsiasi applicazione il cui processo e informazione (come quelle preferenze condivise) rimangono nascoste al resto delle applicazioni. Un'applicazione Android in esecuzione in un pacchetto non può accedere direttamente a nulla all'interno di un altro pacchetto. Ecco perché le applicazioni nello stesso pacchetto (che sono sempre le tue) potrebbero accedere alle informazioni di altri
Korcholis,

@Reto Meier il mio requisito è proteggere i servizi Web disponibili al pubblico per cui sto utilizzando un token, è sicuro archiviarlo nelle preferenze condivise? ho un ricevitore di trasmissione di avvio nella mia applicazione che eliminerà tutti i dati di preferenze condivise se ha trovato il dispositivo come rootato. È abbastanza per proteggere il mio token.
pyus13

1
Per android-developers.blogspot.com/2013/02/… , le credenziali dell'utente devono essere archiviate con il flag flag MODE_PRIVATE e archiviate nella memoria interna (con gli stessi avvertimenti sulla memorizzazione di qualsiasi tipo di password localmente aperta alla fine all'attacco). Detto questo, l'utilizzo MODE_PRIVATEcon SharedPreferences equivale a fare lo stesso con un file creato nella memoria interna, in termini di efficacia per offuscare i dati memorizzati localmente?
qix,

6
Non memorizzare una password nelle preferenze condivise. Se l'utente perde il telefono, ha perso la password. Verrà letto. Se hanno usato quella password altrove, ovunque lo abbiano usato è compromessa. Inoltre, hai perso definitivamente questo account perché con la password possono cambiare la tua password. Il modo corretto per farlo è inviare una volta la password al server e ricevere nuovamente un token di accesso. Archivia quello nelle preferenze condivise e invialo con ogni richiesta. Se quel token viene compromesso, nient'altro viene perso.
Gabe Sechan,

211

Sono d'accordo con Reto e fiXedd. Parlare oggettivamente non ha molto senso investire tempo e sforzi significativi nella crittografia delle password in SharedPreferences poiché qualsiasi utente malintenzionato che ha accesso al file delle preferenze è abbastanza probabile che abbia anche accesso al file binario dell'applicazione, e quindi le chiavi per decodificare il parola d'ordine.

Tuttavia, detto ciò, sembra esserci un'iniziativa pubblicitaria in corso per identificare le applicazioni mobili che memorizzano le loro password in chiaro in SharedPreferences e che fanno luce su tali applicazioni sfavorevoli. Vedi http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/ e http://viaforensics.com/appwatchdog per alcuni esempi.

Sebbene occorra prestare maggiore attenzione alla sicurezza in generale, direi che questo tipo di attenzione su questo particolare problema in realtà non aumenta in modo significativo la nostra sicurezza complessiva. Tuttavia, essendo le percezioni così come sono, ecco una soluzione per crittografare i dati inseriti in SharedPreferences.

Basta avvolgere il proprio oggetto SharedPreferences in questo e tutti i dati letti / scritti verranno automaticamente crittografati e decrittografati. per esempio.

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

Ecco il codice per la classe:

/**
 * 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 è disponibile nel livello API 8 (2.2) e versioni successive. Puoi utilizzare iharder.sourceforge.net/current/java/base64 o qualcos'altro per i sistemi operativi precedenti.
emmby,

34
Sì, ho scritto questo. Sentiti libero di usare, nessuna attribuzione necessaria
emmby

8
Sono d'accordo con te. Ma se la password viene utilizzata solo sul server, perché non utilizzare la crittografia della chiave pubblica / privata? Chiave pubblica sul client durante il salvataggio della password. Il client non dovrà mai leggere nuovamente la password in chiaro, giusto? Il server può quindi decodificarlo con la chiave privata. Quindi, anche se qualcuno passa attraverso il codice sorgente della tua app, non può ottenere la password, tranne per aver hackerato il tuo server e ottenere la chiave privata.
Patrick Boos,

4
Ho aggiunto alcune funzionalità a questo codice e l'ho messo su github su github.com/RightHandedMonkey/WorxForUs_Library/blob/master/src/… . Ora gestisce la migrazione delle preferenze non crittografate a quelle crittografate. Inoltre genera la chiave in fase di esecuzione, quindi la decompilazione dell'app non rilascia la chiave.
RightHandedMonkey il

3
Aggiunta tardiva, ma il commento di @PatrickBoos è un'ottima idea. Un problema con questo, tuttavia, è che anche se hai crittografato la password, un utente malintenzionato che ha rubato quel codice sarebbe comunque in grado di accedere ai tuoi server, perché i server eseguono la decrittografia. Un'aggiunta a questo approccio è quella di crittografare la password insieme a un timestamp. In questo modo puoi decidere, ad esempio, di consentire solo le password salvate nel recente passato (come l'aggiunta di una data di scadenza al tuo "token") o persino la richiesta a determinati utenti di avere un timestamp da una data particolare ("revociamo" vecchi "token").
Adevine,

29

Il modo più semplice per memorizzare una singola preferenza in un'attività Android è fare qualcosa del genere:

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

Se sei preoccupato per la sicurezza di questi, puoi sempre crittografare la password prima di memorizzarla.


9
Non potrei essere più d'accordo con te su questo approccio semplicistico; tuttavia, dovresti sempre essere preoccupato per la sicurezza delle password che memorizzi? A seconda della tua applicazione, hai potenziali responsabilità per informazioni personali rubate. Basta sottolineare questo per chiunque cerchi di archiviare password effettive su cose come conti bancari o qualcosa di altrettanto importante. Ti voto comunque comunque.
While-E,

1
Dove vorresti conservare la chiave che memorizzava la password? Se le preferenze condivise sono accessibili da altri utenti, lo è anche la chiave.
OrhanC1,

@ OrhanC1 hai ricevuto la risposta.?
eRaisedToX,

10

Utilizzando lo snippet fornito da Richard, è possibile crittografare la password prima di salvarla. L'API delle preferenze, tuttavia, non fornisce un modo semplice per intercettare il valore e crittografarlo: puoi bloccarlo mentre viene salvato tramite un listener OnPreferenceChange e teoricamente potresti modificarlo tramite un preferenzaChangeListener, ma ciò si traduce in un ciclo infinito.

In precedenza avevo suggerito di aggiungere una preferenza "nascosta" per raggiungere questo obiettivo. Non è sicuramente il modo migliore. Presenterò altre due opzioni che ritengo più praticabili.

Innanzitutto, il più semplice, è in un oggetto DefinitionChangeListener, è possibile acquisire il valore immesso, crittografarlo e quindi salvarlo in un file di preferenze 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; 
   }

Il secondo modo, e il modo che preferisco ora, è quello di creare le tue preferenze personalizzate, estendendo EditTextPreference, @ Override'ing i metodi setText()e getText(), in modo che setText()crittografa la password e getText()restituisca null.


So che è piuttosto vecchio, ma ti dispiacerebbe pubblicare il tuo codice per la tua versione personalizzata di EditTextPreference, per favore?
RenniePet,

Non importa, ho trovato un esempio utilizzabile qui groups.google.com/forum/#!topic/android-developers/pMYNEVXMa6M e ora ho funzionato. Grazie per aver suggerito questo approccio.
RenniePet,

6

Va bene; è passato un po 'di tempo da quando la risposta è un po' mista, ma ecco alcune risposte comuni. Ho studiato questo come un matto ed è stato difficile costruire una buona risposta

  1. Il metodo MODE_PRIVATE è considerato generalmente sicuro, se si presume che l'utente non abbia effettuato il root del dispositivo. I tuoi dati sono memorizzati in testo semplice in una parte del file system a cui è possibile accedere solo dal programma originale. Ciò consente di afferrare facilmente la password con un'altra app su un dispositivo rooted. Poi di nuovo, vuoi supportare i dispositivi rooted?

  2. AES è ancora la migliore crittografia che puoi fare. Ricordati di cercarlo se stai avviando una nuova implementazione se è passato un po 'di tempo da quando l'ho pubblicato. Il problema più grande con questo è "Cosa fare con la chiave di crittografia?"

Quindi, ora siamo al "Cosa fare con la chiave?" porzione. Questa è la parte difficile. Ottenere la chiave non è poi così male. Puoi usare una funzione di derivazione della chiave per prendere una password e renderla una chiave abbastanza sicura. Ti imbatti in problemi come "quanti passaggi fai con PKFDF2?", Ma questo è un altro argomento

  1. Idealmente, si memorizza la chiave AES dal dispositivo. Devi trovare un buon modo per recuperare la chiave dal server in modo sicuro, affidabile e sicuro però

  2. Hai una sequenza di accesso di qualche tipo (anche la sequenza di accesso originale che fai per l'accesso remoto). Puoi eseguire due esecuzioni del tuo generatore di chiavi con la stessa password. Il modo in cui funziona è che si ottiene la chiave due volte con un nuovo sale e un nuovo vettore di inizializzazione sicuro. Memorizzi una di quelle password generate sul dispositivo e usi la seconda password come chiave AES.

Quando si accede, si ricava nuovamente la chiave sull'accesso locale e la si confronta con la chiave memorizzata. Fatto ciò, si utilizza la chiave derivata n. 2 per AES.

  1. Utilizzando l'approccio "generalmente sicuro", crittografate i dati utilizzando AES e memorizzate la chiave in MODE_PRIVATE. Questo è raccomandato da un recente post sul blog Android. Non incredibilmente sicuro, ma molto meglio per alcune persone con il semplice testo

Puoi fare molte varianti di questi. Ad esempio, anziché una sequenza di accesso completa, è possibile eseguire un PIN rapido (derivato). Il PIN rapido potrebbe non essere sicuro come una sequenza di accesso completa, ma è molte volte più sicuro del semplice testo


5

So che questo è un po 'di negromanzia, ma dovresti usare Android AccountManager . È appositamente progettato per questo scenario. È un po 'ingombrante ma una delle cose che fa è invalidare le credenziali locali se la scheda SIM cambia, quindi se qualcuno scorre il telefono e lancia una nuova SIM al suo interno, le tue credenziali non saranno compromesse.

Ciò offre inoltre all'utente un modo rapido e semplice per accedere (e potenzialmente eliminare) le credenziali archiviate per qualsiasi account che hanno sul dispositivo, il tutto da un'unica posizione.

SampleSyncAdapter è un esempio che utilizza le credenziali dell'account memorizzate.


1
Si noti che l'utilizzo di AccountManager non è più sicuro di qualsiasi altro metodo fornito sopra! developer.android.com/training/id-auth/…
Sander Versluys

1
Il caso d'uso di AccountManager è quando l'account deve essere condiviso tra app diverse e app di autori diversi. Memorizzare la password e fornirla a qualsiasi app richiedente non sarebbe appropriato. Se l'utilizzo dell'utente / password è solo per una singola app, non utilizzare AccountManager.
dolmen,

1
@dolmen, non è del tutto corretto. AccountManager non fornirà la password dell'account a nessuna app il cui UID non corrisponda a quello dell'autenticatore. Il nome sì; il token di autenticazione, sì; la password, no. Se ci provi, genererà SecurityException. E il caso d'uso è molto più ampio di quello. developer.android.com/training/id-auth/identify.html
Jon O

5

Getterò il cappello sul ring solo per parlare di proteggere le password in generale su Android. Su Android, il file binario del dispositivo deve essere considerato compromesso: questo è lo stesso per qualsiasi applicazione finale che è sotto il controllo diretto dell'utente. Concettualmente, un hacker potrebbe utilizzare l'accesso necessario al file binario per decompilarlo e sradicare le password crittografate ed ecc.

Pertanto, ci sono due suggerimenti che vorrei lanciare lì se la sicurezza è una delle maggiori preoccupazioni per te:

1) Non memorizzare la password effettiva. Memorizzare un token di accesso concesso e utilizzare il token di accesso e la firma del telefono per autenticare il lato server della sessione. Il vantaggio è che puoi fare in modo che il token abbia una durata limitata, non stai compromettendo la password originale e hai una buona firma che puoi utilizzare per correlare al traffico in un secondo momento (ad esempio per verificare i tentativi di intrusione e invalidare il token che lo rende inutile).

2) Utilizzare l'autenticazione a 2 fattori. Questo può essere più fastidioso e invadente, ma per alcune situazioni di conformità inevitabili.



2

Questa è una risposta supplementare per coloro che arrivano qui in base al titolo della domanda (come ho fatto io) e non è necessario affrontare i problemi di sicurezza relativi al salvataggio delle password.

Come utilizzare le preferenze condivise

Le impostazioni dell'utente vengono generalmente salvate localmente in Android utilizzando SharedPreferencesuna coppia chiave-valore. Utilizzare la Stringchiave per salvare o cercare il valore associato.

Scrivi in ​​Preferenze condivise

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

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

Utilizzare apply()invece di commit()salvare in background anziché immediatamente.

Leggi dalle preferenze condivise

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

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

Il valore predefinito viene utilizzato se la chiave non viene trovata.

Appunti

  • Invece di usare una stringa di chiave locale in più punti come ho fatto sopra, sarebbe meglio usare una costante in una singola posizione. È possibile utilizzare qualcosa di simile nella parte superiore dell'attività delle impostazioni:

      final static String PREF_MY_INT_KEY = "myInt";
  • Ho usato un intnel mio esempio, ma è anche possibile utilizzare putString(), putBoolean(), getString(), getBoolean(), etc.

  • Vedi la documentazione per maggiori dettagli.

  • Esistono diversi modi per ottenere le preferenze condivise. Vedi questa risposta per cosa cercare.


1

Questa risposta si basa su un approccio suggerito da Mark. Viene creata una versione personalizzata della classe EditTextPreference che converte avanti e indietro tra il testo normale visualizzato nella vista e una versione crittografata della password archiviata nella memoria delle preferenze.

Come è stato sottolineato dalla maggior parte di coloro che hanno risposto a questo thread, questa non è una tecnica molto sicura, sebbene il grado di sicurezza dipenda in parte dal codice di crittografia / decodifica utilizzato. Ma è abbastanza semplice e conveniente e vanificherà lo snooping più casual.

Ecco il codice per la classe EditTextPreference personalizzata:

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

Questo mostra come può essere usato - questo è il file "items" che guida la visualizzazione delle preferenze. Si noti che contiene tre normali viste EditTextPreference e una delle viste personalizzate 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>

Per quanto riguarda la crittografia / decrittografia effettiva, ciò viene lasciato come esercizio per il lettore. Attualmente sto usando del codice basato su questo articolo http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/ , sebbene con valori diversi per la chiave e il vettore di inizializzazione.


1

Prima di tutto penso che i dati dell'utente non debbano essere archiviati sul telefono, e se è necessario archiviare i dati da qualche parte sul telefono, dovrebbero essere crittografati nei dati privati ​​delle app. La sicurezza delle credenziali degli utenti dovrebbe essere la priorità dell'applicazione.

I dati sensibili dovrebbero essere archiviati in modo sicuro o per niente. In caso di perdita del dispositivo o infezione da malware, i dati archiviati in modo non sicuro possono essere compromessi.


1

Uso Android KeyStore per crittografare la password utilizzando RSA in modalità ECB e quindi salvarla in SharedPreferences.

Quando voglio la password indietro, leggo quella crittografata da SharedPreferences e la decrittografare utilizzando il KeyStore.

Con questo metodo si genera una coppia di chiavi pubblica / privata in cui quella privata viene archiviata e gestita in modo sicuro da Android.

Ecco un link su come eseguire questa operazione: Tutorial KeyStore Android


-2

le preferenze condivise sono il modo più semplice per archiviare i dati delle nostre applicazioni. ma è possibile che chiunque possa cancellare i nostri dati delle preferenze condivise tramite il gestore dell'applicazione, quindi non penso che sia completamente sicuro per la nostra applicazione.


-3

è necessario utilizzare sqlite, apit di sicurezza per memorizzare le password. qui è il miglior esempio, che memorizza le password, - passwordsafe. ecco il link per la fonte e la spiegazione: http://code.google.com/p/android-passwordsafe/


3
L'OP deve memorizzare una coppia nome utente e password. Sarebbe ridicolo considerare la creazione di un'intera tabella di database per questo uso
HXCaine

@HXCaine Sono in disaccordo con rispetto - posso vedere almeno 1 altro uso di una tabella sqlite utente / password. SE SI CONSIDERA IL RISCHIO (dell'utilizzo di sqlite) ACCETTABILE, oltre alla semplice autenticazione di accesso all'applicazione, è possibile utilizzare la tabella per archiviare più password ftp (se la tua app utilizza ftp - la mia a volte lo fa), ad esempio. inoltre, la creazione di una classe di adattatori sqlite per questa manipolazione è semplice.
tony gil,

Bella risurrezione di un commento di due anni! Ad essere sinceri, il mio commento è stato un anno dopo la risposta :) Anche con una manciata di password FTP, l'overhead è molto più grande con una tabella SQLite rispetto a SharedPreferences sia in termini di spazio che di codifica. Sicuramente ciò non può essere necessario
HXCaine,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.