MASTG-KNOW-0036: Preferências Compartilhadas

A API SharedPreferences é comumente usada para salvar permanentemente pequenas coleções de pares chave-valor.

Desde o Android 4.2 (API nível 17), o objeto SharedPreferences só pode ser declarado como privado (e não legível globalmente, ou seja, acessível a todos os aplicativos). No entanto, como os dados armazenados em um objeto SharedPreferences são gravados em um arquivo XML em texto simples, seu uso indevido pode frequentemente levar à exposição de dados sensíveis.

Considere o seguinte exemplo:

var sharedPref = getSharedPreferences("key", Context.MODE_PRIVATE)
var editor = sharedPref.edit()
editor.putString("username", "administrator")
editor.putString("password", "supersecret")
editor.commit()

Uma vez que a atividade é chamada, o arquivo key.xml será criado com os dados fornecidos. Este código viola várias práticas recomendadas.

  • O nome de usuário e a senha são armazenados em texto claro em /data/data/<nome-do-pacote>/shared_prefs/key.xml.
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
  <string name="username">administrator</string>
  <string name="password">supersecret</string>
</map>

MODE_PRIVATE torna o arquivo acessível apenas pelo aplicativo que o chamou. Veja "Usar SharedPreferences no modo privado".

Existem outros modos inseguros, como MODE_WORLD_READABLE e MODE_WORLD_WRITEABLE, mas eles foram descontinuados desde o Android 4.2 (API nível 17) e removidos no Android 7.0 (API nível 24). Portanto, apenas aplicativos em execução em uma versão mais antiga do sistema operacional (android:minSdkVersion menor que 17) serão afetados. Caso contrário, o Android lançará uma SecurityException. Se um aplicativo precisar compartilhar arquivos privados com outros aplicativos, é melhor usar um FileProvider com FLAG_GRANT_READ_URI_PERMISSION. Veja Compartilhamento de Arquivos para mais detalhes.

Você também pode usar EncryptedSharedPreferences, que é um wrapper de SharedPreferences que criptografa automaticamente todos os dados armazenados nas preferências compartilhadas.

Aviso

A biblioteca de criptografia de segurança do Jetpack, incluindo as classes EncryptedFile e EncryptedSharedPreferences, foi descontinuada. No entanto, como um substituto oficial ainda não foi lançado, recomendamos usar essas classes até que esteja disponível.

var masterKey: MasterKey? = null
masterKey = Builder(this)
    .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
    .build()

val sharedPreferences: SharedPreferences = EncryptedSharedPreferences.create(
    this,
    "secret_shared_prefs",
    masterKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

val editor = sharedPreferences.edit()
editor.putString("username", "administrator")
editor.putString("password", "supersecret")
editor.commit()