Firebase 身份验证 Android SDK 如何保留刷新令牌?

Dav*_*uel 6 android firebase firebase-authentication

我正在阅读文档,但我找不到 SDK 如何在设备上保留刷新令牌,以便能够在应用程序被终止时保持用户身份验证。

我想了解的是:

  • 刷新令牌的存储位置
  • 如何保护刷新令牌以防止恶意行为者窃取它

有人对此有任何见解吗?

Dav*_*uel 8

创建一个集成 Firebase Auth 的小型演示应用程序并检查它后,我想我找到了我正在寻找的东西:

\n
    \n
  • 刷新令牌存储在哪里?SharedPreferences
  • \n
  • 如何?纯文本形式
  • \n
\n
\n

细节:

\n

Firebase Auth 用于SharedPreferences缓存与经过身份验证的 Firebase 用户相关的所有信息。

\n

存储在SharedPreferences对象中的数据将写入应用程序内部存储目录中的纯文本 XML 文件。该文件可以在以下位置找到:

\n
/data/data/{app_package_name}/shared_prefs/com.google.firebase.auth.api.Store.{hash}.xml\n
Run Code Online (Sandbox Code Playgroud)\n

该文件包含两个键值对,它们都包含刷新令牌:

\n
    \n
  • com.google.firebase.auth.FIREBASE_USER
  • \n
\n
/data/data/{app_package_name}/shared_prefs/com.google.firebase.auth.api.Store.{hash}.xml\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • com.google.firebase.auth.GET_TOKEN_RESPONSE.{hash}
  • \n
\n
{\n  "cachedTokenState": "{\\"refresh_token\\":\\"AIwUa...\\",\\"expires_in\\":3600,\\"token_type\\":\\"Bearer\\",\\"issued_at\\":1651836746042}",\n  "applicationName": "[DEFAULT]",\n  "type": "com.google.firebase.auth.internal.DefaultFirebaseUser",\n  "userInfos": [\n    "{\\"userId\\":\\"sDa2XJk...\\",\\"providerId\\":\\"firebase\\",\\"email\\":\\"user@email.com\\",\\"isEmailVerified\\":false}",\n    "{\\"userId\\":\\"user@email.com\\",\\"providerId\\":\\"password\\",\\"email\\":\\"user@email.com\\",\\"isEmailVerified\\":false}"\n  ],\n  "anonymous": false,\n  "version": "2",\n  "userMetadata": {\n    "lastSignInTimestamp": 1651836746972,\n    "creationTimestamp": 1651579404681\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

安全影响:

\n

非 root 设备中的其他应用程序无法访问存储文件的应用程序的内部存储目录,并且它在 Android 10 或更高版本的设备中进行了加密(因为现在强制执行基于文件的加密)。SharedPreferences

\n

Android 的自动备份会在运行 Android 6 或更高版本的设备上自动将应用程序的内部存储目录备份到 Google Drive。在运行 Android 9 或更高版本的设备上,使用设备的 PIN、图案或密码对备份进行端到端加密。

\n

基于上述情况,刷新令牌可能会在以下情况下(至少)受到损害:

\n
    \n
  • 在获得 root 权限的设备中,具有 root 访问权限的应用程序可以读取SharedPreferences存储刷新令牌的 XML 文件。
  • \n
  • 在 Android < 10 且未启用全磁盘或基于文件的加密的非 root 设备中,具有设备物理访问权限的恶意行为者可以挂载磁盘并读取刷新令牌。
  • \n
  • 使用 创建备份时adb backup,加密备份文件是可选的。如果备份未加密并且恶意行为者获得了备份文件的访问权限,他就可以从中提取刷新令牌。
  • \n
  • 在 Android \xe2\x89\xa5 6 和 < 9 且为应用程序启用自动备份的非 root 设备中,存储在 Google Drive 中的备份文件未进行端到端加密。因此,获得您 Google 帐户访问权限的恶意行为者可以访问备份文件,进而访问刷新令牌。
  • \n
\n

潜在的缓解措施:

\n
    \n
  • 添加 root 检测以警告用户其风险(或假设拥有 root 手机的用户已经意识到这些风险)。
  • \n
  • 如果未启用,建议用户启用加密。
  • \n
  • 从备份中排除 Firebase 身份验证SharedPreferences文件。
  • \n
\n

但如果您需要完全遵守OWASPMSTG-STORAGE-1规则

\n
\n

系统凭证存储设施需要用于存储敏感数据,例如 PII、用户凭证或加密密钥。

\n
\n

那么您唯一的选择是使用 Firebase 身份验证 REST API 而不是使用其 SDK,并使用适当的加密存储(例如EncryptedSharedPreferences )自行保留刷新令牌。

\n

否则,您可以考虑一些默认情况下在其 SDK 中支持加密的替代提供商,例如:

\n\n

此测试是针对 Firebase Auth v21.0.3 执行的,该版本是撰写本文时的最新版本。

\n
\n

更新: \n我发现Firebase 团队关于他们的方法的声明:

\n
\n

至于命名的 SharedPreferences 文件,com.google.firebase.auth.api.Store.{code}.xml实际上就是我们保存用户状态的地方。当应用程序进入后台或关闭时,当前登录的用户需要存储在某个地方,而 SharedPreferences 是一个安全的地方 - 它具有私有文件系统权限,这意味着只有该应用程序(或具有 root 权限的进程)权限)可以读取它。因此,加密是没有必要的。一般来说,Firebase 只对未 root 的、非用户调试的设备提供安全保证;root 或 userdebug 设备的安全属性显着降低,而我们无法正确解释。

\n

不过,问题仍然存在,为什么我们不加密存储中的内容?答案非常简单:它不提供额外的安全性(除了隐匿性安全性之外),并且会降低性能和复杂性。例如,root 用户还可以作为目标应用程序访问 Android 密钥库,这意味着他们仍然可以读取 SharedPreferences,他们只需首先读取并使用适当的密钥即可。

\n
\n