在 Android 中使用生物識別

爲了保護隱私和敏感數據,應用每每會增長用戶登陸功能。若是您的應用使用了傳統的登陸方式,那麼它的受權過程可能相似如圖 1 中所示: 用戶輸入用戶名和密碼,應用會根據輸入的數據生成設備憑據,而後將其發送到遠端服務器進行驗證,經過驗證後會返回給應用一個 userToken,隨後應用即可使用該 token 去服務器查詢受限的用戶數據。不管是要求用戶每次打開應用都須要登陸,仍是隻要求在安裝啓動後進行僅此一次的登陸,圖 1 所示的流程都適用。html

△ 圖 1: 未使用生物識別的受權流程

△ 圖 1: 未使用生物識別的受權流程java

然而,圖 1 這種受權方式有一些弊端:android

  • 若是對於每次獨立的會話都須要進行驗證 (好比銀行類的應用),那麼這套流程會讓用戶感到很是繁瑣,由於每次打開應用都須要輸入一遍密碼;
  • 若是驗證發生在應用首次安裝後打開時 (好比郵件類應用),那麼擁有該設備的任何人均可以查看設備全部者的隱私內容,由於應用沒法驗證當前使用者是否爲設備全部者本人。

爲了彌補這些弊端,咱們引入了生物識別身份驗證的方式,爲終端用戶的身份驗證流程提供了諸多便利。不只如此,這套技術對開發者也更具吸引力,即便業務邏輯可能不須要用戶頻繁登陸。使用生物識別身份驗證帶來的最關鍵的好處在於,整個認證過程十分簡短,只須要輕按一下傳感器或是看一眼設備就完成了。而做爲開發者,您要肯定您的用戶必需要進行從新認證的頻率,是一天一次,一週一次仍是每次打開應用都須要從新認證。總而言之,咱們提供的 API 封裝了許多功能,使開發者及其用戶得到更加友好方便的登陸體驗。api

現在,許多處理我的數據的應用 (例如郵件或社交應用) 在安裝後每每只須要進行一次性身份驗證。這種作法普及起來,是由於每次打開應用都須要輸入用戶名和密碼的方式對用戶體驗形成了不良影響。但如果使用了生物識別技術,用戶便再也不擔憂安全性的缺失。即便您的應用仍是使用一次性的身份驗證,也能夠考慮按期進行生物特徵識別,以驗證是否爲同一用戶。驗證週期的長短徹底取決於開發者的設定。安全

  • 若是應用要求每次獨立會話都須要進行驗證 (或者是某些較爲頻繁的認證頻率,例如每 2 小時一次或者天天一次等等),那麼相比每次都手動輸入密碼進行驗證的話,看一眼設備或輕按一下傳感器這種方式就只是一種微不足道的操做。
  • 若是應用僅需在安裝後進行一次性驗證 (例如郵件類應用),那麼添加生物識別功能的代價只是讓用戶多了一個拿起設備而後看一眼的操做,但卻額外提供了更加安全的保障。
  • 若是用戶但願無需額外進行驗證,仍可以保持郵件的打開狀態,那麼應該提供選項容許這種行爲。

對於想得到更多隱私保護的用戶,生物識別功能可以提供額外的安心保障。不管哪一種方式,同增長的收益相比,用戶所付出的成本微乎其微。服務器

使用 BiometricPrompt API 實現生物識別功能

經過 BiometricPrompt API,您能夠在加密和不加密的狀況下實現身份驗證。若是您的應用須要更強安全性的保障 (例如醫療類或銀行類應用),則可能須要 將加密密鑰同生物特徵綁定在一塊兒 來驗證用戶的身份。不然您僅需向用戶提供生物識別身份驗證便可。兩種方式的代碼實現很相似,除了在須要加密時要用到 CryptoObject 實例。app

加密版本:框架

biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))

在上述代碼中,咱們向 CryptoObject 傳遞了 Cipher 參數,除此以外也支持其他加密對象,好比使用 MacSignatureui

不使用 CryptoObject 的版本:google

biometricPrompt.authenticate(promptInfo)

若要在 Android 應用中實現生物識別身份驗證,請使用 AndroidX Biometric 代碼庫。雖然 API 能夠自動處理不一樣的認證級別 (指紋、面部識別、虹膜識別等),但您仍然能夠經過 setAllowedAuthenticators() 方法設置應用能夠接受的生物認證級別,具體以下面的代碼所示。Class 3 (之前被稱爲 Strong) 級別表明您但願使用生物識別來解鎖存儲在 Keystore 中的憑證;Class 2 (之前被稱爲 Weak) 級別表明您只須要使用生物識別來解鎖應用,而不依賴於加密技術保護的憑證進一步進行身份驗證。還有一個 Class 1 級別,但此級別在應用中並不可用。更多詳情,請查看 Android 兼容性定義文檔

fun createPromptInfo(activity: AppCompatActivity): BiometricPrompt.PromptInfo =

   BiometricPrompt.PromptInfo.Builder().apply {

      setAllowedAuthenticators(BIOMETRIC_STRONG)
     //  繼續設置其餘 PromptInfo 屬性,如標題、副標題、描述等。
}.build()

加密、auth-per-use (每次驗證) 密鑰 vs time-bound (時間限制) 密鑰

auth-per-use 密鑰 是一種被用來執行一次性加密操做的密鑰。舉個例子,若是您想執行 10 次加密操做,那麼就必須解鎖 10 次密鑰。所以,auth-per-use 就意味着每次使用密鑰時,都必須進行認證 (即解鎖密鑰)。

time-bound 密鑰 則是一種在必定的時間段內有效的密鑰,您經過向 setUserAuthenticationValidityDurationSeconds 方法傳遞一個以秒爲單位的時間參數,過了該時間後該密鑰就須要再次進行解鎖。若是您傳遞的時間參數值爲 -1,也就是默認值,那麼系統會認爲您想要使用 auth-per-use 密鑰。在這裏若您不想設置爲 -1,那麼咱們建議您至少設置爲 3 秒,這樣系統會遵循您所設置的時間。想要了解更多建立 time-bound 密鑰的方法,請參考 Jetpack Security 中關於 MasterKeys 的內容。

一般,即前面提到的 -1 的狀況時,您經過向 BiometricPrompt.authenticate() 方法傳遞一個 CryptoObject 參數來請求 auth-per-use 密鑰。然而,您也能夠不使用 CryptoObject,而是設置一個很短的時間參數 (好比 5 秒),來將 time-bound 密鑰看成 auth-per-use 密鑰來使用。這兩種方法對於驗證用戶身份來講其實是等同的,如何選擇取決於您設計應用交互的方式。

讓咱們看看這兩種不一樣類型的密鑰是如何工做的: 當您使用 CryptoObject 時,只有某個特定操做纔可以解鎖密鑰。這是由於 Keymint (或者是 Keymaster) 獲取了一個帶有特定 operationId 的 HardwareAuthToken (HAT)。當密鑰被解鎖後,您只能使用密鑰去執行那些被定義爲 Cipher/Mac/Signature 的操做,並只能執行一次,由於這是一個 auth-per-use 密鑰。若不使用 CryptoObject,那麼被髮送到 Keymint 的 HAT 就沒有 operationId,此時,Keymint 會去查找一個帶有有效時間戳 (時間戳 + 密鑰使用期限 > 當前時間) 的 HAT,在有效時間內,您都可以使用該密鑰,由於它是一個 time-bound 密鑰。

這樣看上去,彷佛只要在有效的時間窗口內,任何應用均可以使用 time-bound 密鑰。但實際上,只要不是用戶空間 (user-space) 受到損害,不用擔憂某個 X 應用使用了某 Y 應用的密鑰或操做。Android 框架不會容許其餘應用獲取或者初始化另外一個應用的操做。

總結

在本篇文章中,咱們介紹了:

  • 只有用戶名 + 密碼的認證方式存在問題的緣由;
  • 在應用中選擇使用生物識別身份驗證的緣由;
  • 不一樣類型應用在設計認證方式時的注意事項;
  • 如何在啓用或未啓用加密的狀況下調用 BiometricPrompt
  • auth-per-usetime-bound 兩種加密密鑰的不一樣。

在下一篇文章中,咱們將爲您帶來如何合理地將生物識別身份驗證的流程整合到應用的 UI 和業務邏輯中。敬請關注!