Qual é a maneira mais apropriada de armazenar as configurações do usuário no aplicativo Android


308

Estou criando um aplicativo que se conecta ao servidor usando nome de usuário / senha e gostaria de ativar a opção "Salvar senha" para que o usuário não precise digitar a senha sempre que o aplicativo for iniciado.

Eu estava tentando fazer isso com preferências compartilhadas, mas não tenho certeza se essa é a melhor solução.

Gostaria de receber qualquer sugestão sobre como armazenar valores / configurações do usuário no aplicativo Android.

Respostas:


233

Em geral, SharedPreferences é sua melhor aposta para armazenar preferências, portanto, em geral, eu recomendaria essa abordagem para salvar as configurações do aplicativo e do usuário.

A única área de preocupação aqui é o que você está salvando. As senhas são sempre uma coisa complicada de armazenar, e eu seria particularmente cauteloso em armazená-las como texto não criptografado. A arquitetura do Android é tal que as SharedPreferences do seu aplicativo são protegidas por sandbox para impedir que outros aplicativos possam acessar os valores, para que haja segurança lá, mas o acesso físico a um telefone pode permitir o acesso aos valores.

Se possível, eu consideraria modificar o servidor para usar um token negociado para fornecer acesso, algo como OAuth . Como alternativa, pode ser necessário construir algum tipo de armazenamento criptográfico, embora isso não seja trivial. No mínimo, verifique se você está criptografando a senha antes de gravá-la no disco.


3
Poderia explicar o que você quer dizer com sandboxed?
Abhijit

14
um programa em área restrita é qualquer aplicativo cujo processo e informações (como essas preferências compartilhadas) permaneçam ocultos dos demais aplicativos. Um aplicativo Android em execução em um pacote não pode acessar diretamente nada dentro de outro pacote. É por isso que aplicativos no mesmo pacote (que sempre são seus) podem acessar informações de outros
Korcholis

@Reto Meier, meu requisito é proteger os serviços da Web publicamente disponíveis, pois estou usando um token; o armazenamento em preferências compartilhadas é seguro? Eu tenho um receptor de transmissão de inicialização no meu aplicativo que excluirá todos os dados de preferências compartilhadas se encontrar o dispositivo como root. Isso é suficiente para proteger meu token?
pyus13

1
De acordo com android-developers.blogspot.com/2013/02/… , as credenciais do usuário devem ser armazenadas com o sinalizador MODE_PRIVATE definido e armazenado no armazenamento interno (com as mesmas ressalvas sobre o armazenamento de qualquer tipo de senha localmente aberta ao ataque). Dito isto, usar MODE_PRIVATEcom SharedPreferences equivale a fazer o mesmo com um arquivo criado no armazenamento interno, em termos de eficácia para ofuscar os dados armazenados localmente?
Qix #

6
Não armazene uma senha em preferências compartilhadas. Se o usuário perder o telefone, ele perderá a senha. Será lido. Se eles usaram essa senha em outro lugar, em todos os lugares em que a usaram está comprometida. Além disso, você perdeu esta conta permanentemente porque, com a senha, eles podem alterar sua senha. A maneira correta de fazer isso é enviar a senha ao servidor uma vez e receber um token de login novamente. Armazene isso na preferência compartilhada e envie-o com cada solicitação. Se esse token for comprometido, nada mais será perdido.
Gabe Séchan

211

Eu concordo com Reto e fiXedd. Objetivamente, não faz muito sentido investir tempo e esforço significativos na criptografia de senhas em SharedPreferences, já que qualquer invasor que tenha acesso ao seu arquivo de preferências provavelmente também terá acesso ao binário do aplicativo e, portanto, às chaves para descriptografar o arquivo. senha.

No entanto, dito isso, parece haver uma iniciativa de publicidade identificando aplicativos móveis que armazenam suas senhas em texto não criptografado em SharedPreferences e lançando luz desfavorável sobre esses aplicativos. Consulte http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/ e http://viaforensics.com/appwatchdog para alguns exemplos.

Embora necessitemos de mais atenção à segurança em geral, eu argumentaria que esse tipo de atenção nessa questão em particular não aumenta significativamente nossa segurança geral. No entanto, como as percepções são como são, aqui está uma solução para criptografar os dados que você coloca em SharedPreferences.

Simplesmente envolva seu próprio objeto SharedPreferences neste e todos os dados que você ler / gravar serão automaticamente criptografados e descriptografados. por exemplo.

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

Aqui está o código da 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
O FYI Base64 está disponível na API nível 8 (2.2) e posterior. Você pode usar iharder.sourceforge.net/current/java/base64 ou outra coisa para sistemas operacionais anteriores.
emmby

34
Sim, eu escrevi isso. Sinta-se livre para usar, sem atribuição necessária
emmby

8
Eu concordo com você. Mas se a senha é usada apenas no servidor, por que não usar a criptografia de chave pública / privada? Chave pública no cliente ao salvar a senha. O cliente nunca mais precisará ler a senha em texto não criptografado, certo? O servidor pode então descriptografá-lo com a chave privada. Portanto, mesmo se alguém passar pelo código-fonte do seu aplicativo, ele não poderá obter a senha, exceto que invadirá o servidor e obterá a chave privada.
Patrick Boos

4
Adicionei alguns recursos a esse código e o coloquei no github em github.com/RightHandedMonkey/WorxForUs_Library/blob/master/src/… . Agora ele lida com a migração de preferências não criptografadas para a criptografada. Também gera a chave no tempo de execução, portanto, a descompilação do aplicativo não libera a chave.
RightHandedMonkey

3
Adição tardia, mas o comentário de @PatrickBoos é uma ótima idéia. Um problema com isso, porém, é que, mesmo que você tenha criptografado a senha, um invasor que roubou essa cifra ainda poderá fazer login nos seus servidores, porque seus servidores fazem a descriptografia. Uma adição a essa abordagem é criptografar a senha junto com um carimbo de data / hora. Dessa forma, você pode decidir, por exemplo, permitir apenas senhas salvas no passado recente (como adicionar uma data de validade ao seu "token") ou até exigir que certos usuários tenham um carimbo de data e hora desde uma data específica (vamos "revogar" "tokens" antigos).
adevine

29

A maneira mais simples de armazenar uma única preferência em uma Atividade Android é fazer algo como isto:

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

Se você estiver preocupado com a segurança desses, sempre poderá criptografar a senha antes de armazená-la.


9
Não concordo mais com você sobre essa abordagem simplista; no entanto, você deve sempre se preocupar com a segurança das senhas armazenadas? Dependendo do seu aplicativo, você tem responsabilidades em potencial por informações pessoais roubadas. Apenas aponte isso para qualquer pessoa que tente armazenar senhas reais em coisas como contas bancárias ou algo igualmente importante. Eu ainda voto em você.
Enquanto-E

1
Onde você armazenaria a chave que armazenava a senha? Se as preferências compartilhadas são acessíveis por outros usuários, a chave também é.
precisa saber é o seguinte

@ OrhanC1 você conseguiu a resposta.?
eRaisedToX 19/08/19

10

Usando o trecho fornecido por Richard, você pode criptografar a senha antes de salvá-la. A API de preferências, no entanto, não fornece uma maneira fácil de interceptar o valor e criptografá-lo - você pode impedir que ele seja salvo por meio de um ouvinte do OnPreferenceChange e, teoricamente, pode modificá-lo por meio de um preferencialChangeListener, mas isso resulta em um loop infinito.

Eu sugeri anteriormente adicionar uma preferência "oculta" para fazer isso. Definitivamente, não é o melhor caminho. Vou apresentar duas outras opções que considero mais viáveis.

Primeiro, o mais simples, está em uma preferênciaChangeListener, você pode pegar o valor digitado, criptografá-lo e salvá-lo em um arquivo de preferências 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; 
   }

A segunda maneira, e da maneira que agora prefiro, é criar sua própria preferência personalizada, estendendo EditTextPreference, @ Substituindo os métodos setText()e getText(), de modo que setText()criptografa a senha e getText()retorne nulo.


Sei que isso é bastante antigo, mas você se importaria de postar seu código para sua versão personalizada do EditTextPreference, por favor?
RenniePet

Não importa, encontrei uma amostra utilizável aqui groups.google.com/forum/#!topic/android-developers/pMYNEVXMa6M e estou trabalhando agora. Obrigado por sugerir essa abordagem.
RenniePet

6

OK; já faz um tempo desde que a resposta é meio confusa, mas aqui estão algumas respostas comuns. Eu pesquisei isso como um louco e foi difícil criar uma boa resposta

  1. O método MODE_PRIVATE é considerado geralmente seguro, se você assumir que o usuário não fez root no dispositivo. Seus dados são armazenados em texto sem formatação em uma parte do sistema de arquivos que pode ser acessada apenas pelo programa original. Isso cria facilmente a senha com outro aplicativo em um dispositivo enraizado. Então, novamente, você deseja suportar dispositivos enraizados?

  2. O AES ainda é a melhor criptografia que você pode fazer. Lembre-se de procurar isso se estiver iniciando uma nova implementação, já faz um tempo desde que eu publiquei isso. O maior problema com isso é "O que fazer com a chave de criptografia?"

Então, agora estamos no "O que fazer com a chave?" parte. Esta é a parte difícil. Obter a chave acaba não sendo tão ruim. Você pode usar uma função de derivação de chave para obter alguma senha e torná-la uma chave bastante segura. Você se depara com questões como "quantas passagens você faz com o PKFDF2?", Mas esse é outro tópico

  1. Idealmente, você armazena a chave AES fora do dispositivo. Você precisa descobrir uma boa maneira de recuperar a chave do servidor de maneira segura, confiável e protegida.

  2. Você tem uma sequência de login de algum tipo (mesmo a sequência de login original que você faz para acesso remoto). Você pode executar duas execuções do seu gerador de chaves na mesma senha. Como isso funciona é que você deriva a chave duas vezes com um novo sal e um novo vetor de inicialização segura. Você armazena uma dessas senhas geradas no dispositivo e usa a segunda senha como chave AES.

Ao fazer login, você obtém a chave novamente no logon local e a compara à chave armazenada. Feito isso, use a chave de derivação nº 2 para o AES.

  1. Usando a abordagem "geralmente segura", você criptografa os dados usando o AES e armazena a chave em MODE_PRIVATE. Isso é recomendado por uma postagem recente no blog do Android. Não é incrivelmente seguro, mas é muito melhor para algumas pessoas em texto simples

Você pode fazer muitas variações disso. Por exemplo, em vez de uma sequência de login completa, você pode fazer um PIN rápido (derivado). O PIN rápido pode não ser tão seguro quanto uma sequência de login completa, mas é muitas vezes mais seguro que o texto sem formatação


5

Sei que isso é um pouco de necromancia, mas você deve usar o Android AccountManager . Foi desenvolvido especificamente para esse cenário. É um pouco complicado, mas uma das coisas que faz é invalidar as credenciais locais se o cartão SIM mudar, por isso, se alguém roubar seu telefone e lançar um novo SIM, suas credenciais não serão comprometidas.

Isso também oferece ao usuário uma maneira rápida e fácil de acessar (e potencialmente excluir) as credenciais armazenadas de qualquer conta que ele possua no dispositivo, tudo em um só local.

SampleSyncAdapter é um exemplo que utiliza credenciais de conta armazenadas.


1
Observe que o uso do AccountManager não é mais seguro do que qualquer outro método fornecido acima! Desenvolvedor.android.com/training/id-auth/…
Sander Versluys

1
O caso de uso do AccountManager é quando a conta deve ser compartilhada entre aplicativos diferentes e aplicativos de autores diferentes. Armazenar a senha e fornecê-la a qualquer aplicativo solicitante não seria apropriado. Se o uso do usuário / senha for apenas para um único aplicativo, não use o AccountManager.
dólmen

1
@ Dolmen, isso não é muito correto. O AccountManager não fornecerá a senha da conta a nenhum aplicativo cujo UID não corresponda ao do autenticador. O nome sim; o token de autenticação, sim; a senha não. Se você tentar, lançará uma SecurityException. E o caso de uso é muito mais amplo que isso. developer.android.com/training/id-auth/identify.html
Jon O

5

Vou jogar meu chapéu no ringue apenas para falar sobre a proteção de senhas em geral no Android. No Android, o binário do dispositivo deve ser considerado comprometido - é o mesmo para qualquer aplicativo final que esteja sob controle direto do usuário. Conceitualmente, um hacker pode usar o acesso necessário ao binário para descompilar e eliminar suas senhas criptografadas, etc.

Como tal, há duas sugestões que eu gostaria de oferecer se a segurança for uma grande preocupação para você:

1) Não armazene a senha real. Armazene um token de acesso concedido e use o token de acesso e a assinatura do telefone para autenticar a sessão no servidor. O benefício disso é que você pode fazer com que o token tenha uma duração limitada, não comprometa a senha original e tem uma boa assinatura que pode ser usada para correlacionar com o tráfego posteriormente (por exemplo, verifique se há tentativas de invasão e invalide o token tornando-o inútil).

2) Utilize autenticação de 2 fatores. Isso pode ser mais irritante e intrusivo, mas para algumas situações de conformidade inevitáveis.



2

Esta é uma resposta suplementar para quem chega aqui com base no título da pergunta (como eu fiz) e não precisa lidar com os problemas de segurança relacionados ao salvamento de senhas.

Como usar Preferências Compartilhadas

As configurações do usuário geralmente são salvas localmente no Android usando SharedPreferencesum par de valores-chave. Você usa a Stringchave para salvar ou procurar o valor associado.

Gravar em preferências compartilhadas

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

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

Use em apply()vez de commit()para salvar em segundo plano em vez de imediatamente.

Ler em Preferências compartilhadas

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

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

O valor padrão é usado se a chave não for encontrada.

Notas

  • Em vez de usar uma chave local String em vários lugares como eu fiz acima, seria melhor usar uma constante em um único local. Você pode usar algo assim na parte superior da atividade de configurações:

    final static String PREF_MY_INT_KEY = "myInt";
  • Eu usei um intno meu exemplo, mas você também pode usar putString(), putBoolean(), getString(), getBoolean(), etc.

  • Veja a documentação para mais detalhes.
  • Existem várias maneiras de obter SharedPreferences. Veja esta resposta para saber o que procurar.

1

Esta resposta é baseada em uma abordagem sugerida por Mark. É criada uma versão personalizada da classe EditTextPreference que converte entre o texto sem formatação visto na exibição e uma versão criptografada da senha armazenada no armazenamento de preferências.

Como foi indicado pela maioria dos que responderam a este tópico, essa não é uma técnica muito segura, embora o grau de segurança dependa parcialmente do código de criptografia / descriptografia usado. Mas é bastante simples e conveniente e impedirá a maioria dos bisbilhoteiros casuais.

Aqui está o código para a classe EditTextPreference personalizada:

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

Isso mostra como ele pode ser usado - este é o arquivo "items" que conduz a exibição das preferências. Observe que ele contém três visualizações EditTextPreference comuns e uma das visualizações EditPasswordPreference personalizadas.

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

Quanto à criptografia / descriptografia real, isso é deixado como um exercício para o leitor. Atualmente, estou usando algum código com base neste artigo http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/ , embora com valores diferentes para a chave e o vetor de inicialização.


1

Antes de tudo, acho que os dados do usuário não devem ser armazenados no telefone e, se for necessário, armazenar dados em algum lugar do telefone, devem ser criptografados nos dados particulares do aplicativo. A segurança das credenciais dos usuários deve ser a prioridade do aplicativo.

Os dados confidenciais devem ser armazenados com segurança ou de maneira alguma. No caso de perda de um dispositivo ou infecção por malware, os dados armazenados de maneira insegura podem ser comprometidos.


1

Uso o KeyStore do Android para criptografar a senha usando o RSA no modo BCE e, em seguida, salve-a nas Preferências compartilhadas.

Quando quero a senha de volta, leio a criptografada das SharedPreferences e descriptografo-a usando o KeyStore.

Com esse método, você gera um par de chaves público / privado, onde o privado é armazenado e gerenciado com segurança pelo Android.

Aqui está um link sobre como fazer isso: Tutorial do Android KeyStore


-2

preferências compartilhadas é a maneira mais fácil de armazenar os dados de nossos aplicativos. mas é possível que alguém possa limpar nossos dados de preferências compartilhadas por meio do gerenciador de aplicativos. Portanto, não acho que seja completamente seguro para nosso aplicativo.


-3

você precisa usar o apit de segurança sqlite para armazenar as senhas. Aqui está o melhor exemplo, que armazena senhas, - passwordsafe. aqui está o link para a fonte e a explicação - http://code.google.com/p/android-passwordsafe/


3
O OP precisa armazenar um par de nome de usuário e senha. Seria ridículo considerar a criação de uma tabela de banco de dados inteiro para este uso
HXCaine

@HXCaine Eu discordo respeitosamente - posso ver pelo menos mais 1 uso de uma tabela sqlite de usuário / senhas. SE VOCÊ CONSIDERAR O RISCO (de usar o sqlite) ACEITÁVEL, além da autenticação simples de login do aplicativo, você pode usar a tabela para armazenar várias senhas ftp (se o seu aplicativo usa ftp-mine às vezes), por exemplo. além disso, a criação de uma classe de adaptador sqlite para esta manipulação é simples.
gil tony

Boa ressurreição de um comentário de dois anos! Para ser sincero, meu comentário foi um ano após a resposta :) Mesmo com algumas senhas de FTP, a sobrecarga é muito maior com uma tabela SQLite do que com SharedPreferences, tanto em termos de espaço quanto de codificação. Certamente que não pode ser necessário
HXCaine
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.