李阳天
Android的密钥库已经推出很多年了,它为应用开发者提供了一种使用加密密钥进行身份验证和加密的方式。密钥库将密钥资料存放在应用的进程空间之外,因此,密钥资料不会在可能受到网络钓鱼攻击的情形下被應用意外透露给用户,不会通过其他某种渠道泄漏,也不会在应用遭到入侵时陷入危险之中。
许多设备也在安全硬件中为密钥库密钥提供基于硬件的安全机制,这种机制将密钥资料完全存储在Android系统之外,因此即使Linux内核遭受入侵,密钥资料也不会泄漏。在绝大多数Android设备中,安全硬件都是主CPU的一种特殊模式,其通过硬件与Linux内核及Android用户空间强制隔离。有些设备还使用单独的安全微处理器。
Android提供的API可以让应用确定给定密钥库密钥是否处于安全硬件中,但是如果操作系统受到入侵,这些API将变得不可靠。密钥认证让设备的安全硬件可以验证某个非对称密钥是否处于安全硬件中,从而在Android OS遭受入侵时为密钥提供保护。
密钥库最初在Android 4.0中引入,密钥采用用户的密码进行加密。Android 4.1添加了使用设备安全硬件的基础架构。
在Android 6.0之前,密钥库仅支持RSA和ECDSA。在Android 6.0中,密钥库得到显著增强,增加了对AES和HMAC的支持。此外,加密运算的其他关键要素(例如RSA补位和AES区块链接模式)也移入安全硬件中。
在Android 6.0中,密钥库还能够限制特定密钥的使用方式。可以应用的最有用限制是用户身份验证绑定。这种限制允许将密钥的使用“绑定”到用户密码(他们的PIN码、图案或口令)或者指纹。对于密码身份验证绑定,应用开发者可以指定一个超时(以秒为单位)。如果自用户上次输入密码以来所经历的时间已超过指定时间,安全硬件将拒绝要求使用密钥的任何请求。指纹绑定密钥在每次使用密钥时都会要求新的用户身份验证。
还可以向Android 6.0+密钥应用其他更多技术限制。特别是,在创建或导入密钥时,需要指定密钥可用于哪些加密目的(加密、解密、签名或验证),为初始化向量或随机数指定补位与分组加密模式、摘要和熵源以及加密运算的其他详细信息。由于指定的信息以加密方式永久绑定到密钥资料上,密钥库将不允许以任何其他方式使用此密钥。因此,已经获取应用或系统控制权限的攻击者无法滥用密钥。为了帮助防止攻击,开发者应为给定密钥指定尽可能窄的用户范围。
Android 7.0中引入了Android密钥库最重要的变更之一。预装Android 7.0+并带有安全锁定屏幕的新发布设备必须具有安全硬件,并支持基于硬件的密码身份验证和密钥库密钥。在Android 7.0之前,安全硬件支持比较分散,不过在未来几年,这项功能将逐渐统一。
在Android 8.0中,密钥认证已成为预装Google Play的所有新设备的强制选项。
为何使用密钥认证?假设您正在开发一款应用,该应用让银行客户可以访问其银行余额、交易历史记录和账单支付系统。安全性至关重要,您肯定不希望捡到用户电话的任何人都能访问用户的银行账户。一种应对方式是使用用户的网站密码。但是这种方式对用户来说通常不方便,因为网站经常需要复杂的长密码,在小型触摸屏上输入这类密码不是很方便。
借助Android密钥库,您可以生成一个非对称的身份验证密钥(例如256位ECDSA密钥),让每位用户使用他们的复杂网络密码登录一次,然后在银行的客户账户数据库中注册公钥。在用户每次打开应用时,您都可以使用该ECDSA密钥执行一次质询,响应身份验证协议。而且,如果您进行密钥身份验证绑定,用户在每次打开应用时还可以使用他们的锁定屏幕密码或指纹进行身份验证。这样一来,他们可以在自己的电话上使用更简单、更方便的身份验证机制。
如果攻击者入侵Android并尝试提取密钥,他们可能会无功而返,因为密钥储存在安全硬件中。
作为一名应用开发者,您可以利用密钥验证在自己的服务器上验证您的应用请求的ECDSA密钥确实位于安全硬件中。请注意,在您的应用中使用验证意义不大;如果Android OS未被入侵并值得信赖,那么您可以直接使用6.0中引入的KeyInfo类来确定密钥是否处于安全硬件中。如果系统已被入侵,那么该API与您在设备上验证密钥认证的任何尝试都是不可靠的。
请注意,密钥认证与SafetyNet认证不同。它们的理念相同,不过认证的对象不同,来源也不同。密钥库密钥认证旨在声明加密密钥位于安全硬件中并且具备指定的某些特性。SafetyNet认证旨在声明设备是真实设备(不是模拟器)并且设备正在运行已知软件。SafetyNet在幕后也使用密钥库密钥认证,因此,如果您想要了解设备完整性,请使用这种认证。如果您想要确认您的密钥位于安全硬件中,请使用密钥认证。