簡體   English   中英

如何在 Android 中安全地存儲訪問令牌和秘密?

[英]How to securely store access token and secret in Android?

我將使用 oAuth 從谷歌獲取郵件和聯系人。 我不想每次都要求用戶登錄以獲取訪問令牌和秘密。 據我了解,我需要將它們與我的應用程序一起存儲在數據庫或SharedPreferences中。 但我有點擔心安全方面的問題。 我讀到你可以加密和解密令牌,但攻擊者很容易反編譯你的 apk 和類並獲取加密密鑰。
將這些令牌安全地存儲在 Android 中的最佳方法是什么?

將它們存儲為共享首選項 這些默認情況下是私有的,其他應用程序無法訪問它們。 在有 root 權限的設備上,如果用戶明確允許訪問某個試圖讀取它們的應用程序,該應用程序可能能夠使用它們,但您無法防止這種情況發生。 至於加密,您必須要求用戶每次都輸入解密密碼(從而破壞了緩存憑據的目的),或者將密鑰保存到文件中,您會遇到同樣的問題。

存儲令牌而不是實際的用戶名密碼有幾個好處:

  • 第三方應用不需要知道密碼,用戶可以確保他們只將密碼發送到原始網站(Facebook、Twitter、Gmail 等)
  • 即使有人竊取了令牌,他們也看不到密碼(用戶也可能在其他網站上使用)
  • 令牌通常具有生命周期並在一定時間后到期
  • 如果您懷疑令牌已被盜用,則可以撤銷令牌

您可以將它們存儲在AccountManager 中 根據這些人的說法,這被認為是最佳實踐。

在此處輸入圖片說明

這是官方定義:

此類提供對用戶在線帳戶的集中注冊表的訪問。 用戶為每個帳戶輸入一次憑據(用戶名和密碼),通過“一鍵式”批准授予應用程序訪問在線資源的權限。

有關如何使用 AccountManager 的詳細指南:

但是,最終 AccountManager 僅將您的令牌存儲為純文本。 因此,我建議在將您的機密存儲在 AccountManager 之前對其進行加密。 您可以使用各種加密庫,如AESCryptAESCrypto

另一種選擇是使用隱藏庫 它對 Facebook 來說足夠安全,而且比 AccountManager 更容易使用。 這是使用隱藏保存機密文件的代碼片段。

byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);

SharedPreferences 本身並不是一個安全的位置。 在有 root 權限的設備上,我們可以輕松讀取和修改所有應用程序的 SharedPrefereces xml。 所以令牌應該相對頻繁地過期。 但即使令牌每小時過期,仍然可以從 SharedPreferences 竊取較新的令牌。 Android KeyStore 應該用於長期存儲和檢索加密密鑰,這些密鑰將用於加密我們的令牌,以便將它們存儲在例如 SharedPreferences 或數據庫中。 密鑰不存儲在應用程序的進程中,因此它們更難被泄露。

因此比地方更重要的是它們如何自身安全,例如使用加密簽名的短期 JWT,使用 Android KeyStore 加密它們並使用安全協議發送它們

  1. 從 Android Studio 的項目窗格中,選擇“項目文件”並在項目的根目錄中創建一個名為“keystore.properties”的新文件。

在此處輸入圖片說明

  1. 打開“keystore.properties”文件並將您的訪問令牌和秘密保存在該文件中。

在此處輸入圖片說明

  1. 現在在您的應用程序模塊的build.gradle文件中加載讀取的訪問令牌和秘密。 然后您需要為您的訪問令牌和秘密定義 BuildConfig 變量,以便您可以直接從您的代碼訪問它們。 您的build.gradle可能如下所示:

     ... ... ... android { compileSdkVersion 26 // Load values from keystore.properties file def keystorePropertiesFile = rootProject.file("keystore.properties") def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) defaultConfig { applicationId "com.yourdomain.appname" minSdkVersion 16 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // Create BuildConfig variables buildConfigField "String", "ACCESS_TOKEN", keystoreProperties["ACCESS_TOKEN"] buildConfigField "String", "SECRET", keystoreProperties["SECRET"] } }
  2. 您可以在代碼中使用您的訪問令牌和秘密,如下所示:

     String accessToken = BuildConfig.ACCESS_TOKEN; String secret = BuildConfig.SECRET;

這樣你就不需要在你的項目中以純文本形式存儲訪問令牌和秘密。 因此,即使有人反編譯了您的 APK,他們也永遠不會在您從外部文件加載它們時獲得您的訪問令牌和機密。

正如這個問題的最新更新一樣,您現在可以使用EncryptedSharedPreferences安全地存儲數據。 界面非常相似,只是您還需要生成一個 MasterKey。

EncryptedSharedPreferences 的大多數文檔都使用 MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC,但似乎不推薦使用MasterKey.Builder

private var masterKeyAlias = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build() 

private val preferences = EncryptedSharedPreferences.create(
            context,
            "auth_token_secured",
            masterKeyAlias,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )

var authToken: String?
    get() = preferences.getString("auth_token", "")
    set(value) = preferences.edit().putString("auth_token", value).apply()

您可以通過以下兩個選項保護您訪問令牌。

  1. 使用將您的訪問令牌保存到不會反向的android密鑰庫中。
  2. 使用NDK函數進行一些計算,使用難以反轉的c ++代碼保存令牌和NDK

Auth0 提供了一個實用程序 class 來存儲令牌。 最好使用那個實用程序庫。 您可以使用兩個類來管理憑據:

  1. CredentialsManager 以純文本形式存儲數據
  2. SecureCredentialsManager 在存儲數據之前使用 RSA 和 AES 算法的組合以及 Android 對數據進行加密
    密鑰庫。

文檔鏈接: Auth0.Android 保存和更新令牌

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM