【问题标题】:AutoBackUp with EncryptedSharedPreferences failing to restore带有 EncryptedSharedPreferences 的 AutoBackUp 无法恢复
【发布时间】:2020-05-12 12:04:32
【问题描述】:

我正在使用EncryptedSharedPreferences在本地存储用户信息(如果您不熟悉,请参阅this)。我已经使用备份规则实现了 AutoBackUp。我备份了首选项,清除了我的应用程序上的数据,并尝试恢复数据(按照for backuprestore 概述的步骤)。

查看 Android Studio 中的设备文件资源管理器,我可以确认我的 Preferences 文件正在恢复(它已正确命名并且其中包含加密数据)。但是,我的应用程序就像首选项文件不存在一样运行。

我错过了什么?

偏好代码:

class PreferenceManager(context: Context) {
    companion object {
        private const val KEY_STORE_ALIAS = "APP_KEY_STORE"
        private const val privatePreferences = "APP_PREFERENCES"
    }

    // See https://developer.android.com/topic/security/data#kotlin for more info
    private val sharedPreferences = EncryptedSharedPreferences.create(
        privatePreferences,
        KEY_STORE_ALIAS,
        context,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )

    init {
        //val all = sharedPreferences.all
        //for (item in all) {
            //Log.e("PREFERENCES", "${item.key} - ${item.value}")
        //}
    }

    @SuppressLint("ApplySharedPref")
    fun clear() {
        // Normally you want apply, but we need the changes to be done immediately
        sharedPreferences.edit().clear().commit()
    }

    fun readBoolean(key: String, defaultValue: Boolean): Boolean {
        return sharedPreferences.getBoolean(key, defaultValue)
    }

    fun readDouble(key: String): Double {
        return sharedPreferences.getFloat(key, 0f).toDouble()
    }

    fun readString(key: String): String {
        return sharedPreferences.getString(key, "")!!
    }

    fun removePreference(key: String) {
        sharedPreferences.edit().remove(key).apply()
    }

    fun writeBoolean(key: String, value: Boolean) {
        sharedPreferences.edit().putBoolean(key, value).apply()
    }

    fun writeDouble(key: String, value: Double) {
        sharedPreferences.edit().putFloat(key, value.toFloat()).apply()
    }

    fun writeString(key: String, value: String) {
        sharedPreferences.edit().putString(key, value).apply()
    }
}

我目前没有实施 BackupAgent。

【问题讨论】:

    标签: android kotlin sharedpreferences backup restore


    【解决方案1】:

    据我了解,Jetpack Security 依赖于在设备硬件上生成的密钥,因此您不能依赖在备份还原后原始密钥仍然存在(考虑更改的设备)。

    加密仅与密钥的安全性一样安全,只要它不能离开 Keystore 或设备,备份和恢复就无法自动工作(无需用户交互)。

    我的方法 (1) 是您要求用户输入密码,根据该密码加密您的常规共享首选项(可能使用另一个加密库:例如 https://github.com/iamMehedi/Secured-Preference-Store),并使用 Jetpack 中的 encryptedsharedpreferences 保存密码.恢复备份后,询问用户密码,使用 Jetpack 再次保存并解密常规 SharedPreferences。 这样,即使硬件密钥库发生更改,您也可以恢复备份。缺点是用户需要记住密码。

    我在我的应用程序中遵循这种方法,但不是使用 sharedpreferences(它们在我的用例中不明智),而是使用应用程序数据库。

    如果您只关心云中的备份,另一种方法 (2) 是检查加密备份(可从 Pie 开始)。使用这种方法,您不会在本地加密共享首选项,但默认情况下会加密备份。如果您需要本地加密,则此方法不适合您,但其优点是,用户只需在恢复备份时输入他/她的锁屏密码,然后无需进一步的用户交互即可恢复所有内容。 如果您可以在没有本地加密的情况下生活,那么组合也是可以考虑的并且是可取的:方法 1 用于 pre-9,方法 2 用于 post-9。

    【讨论】:

    • 不幸的是,本地加密是必须的。谢谢你的详细解释。我暂时将此标记为答案。
    【解决方案2】:

    正如@Floj12 提到的EncryptedSharedPreferences 使用密钥库并且您无法备份密钥库,因此当您的加密数据将被恢复时,您将无法解密它。 谷歌强迫两件不能一起工作的事情是非常可悲的。 Android 上的 Keystore 没有 iOS 上的 Keychain 那样的备份选项。

    这里我会给你更多选择如何备份数据:

    • 一个后端存储用户数据
    • 使用用户存储的令牌解密备份
    • 为所有应用设置静态密码
    • 用户在设置中手动导出备份

    我在这里写了更多关于它的内容: https://medium.com/@thecodeside/android-auto-backup-keystore-encryption-broken-heart-love-story-8277c8b10505

    【讨论】:

      猜你喜欢
      • 2020-09-21
      • 1970-01-01
      • 2022-07-29
      • 1970-01-01
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多