在 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 和业务逻辑中。敬请关注!