开启指纹认证
这里以登录为例,来看看如何使用指纹认证来做APP登录。还是先要注册指纹,具体过程如下图所示:
- 5开启指纹:开启指纹登录的时机,一般都是先用别的方式登录了APP,然后再开启指纹登录。但是也有一些例外,用户使用APP时直接使用第三方登录,第三方提供了指纹登录的方式,比如使用Apple Id登录。上边图中是先用账号密码登录了系统,然后才开启的指纹认证。
- 12对比系统存在的指纹:指纹数据始终保存在手机本地,不会上传到远程。目前市面上的手机都是这样做的,Android和iOS提供的指纹认证API都只返回true或者false的认证结果,这样可以避免云服务被攻破时导致大规模泄漏的严重后果,最大限度的保护用户生物特征数据的安全。
- 13指纹验证成功:本地指纹认证通过就代表用户身份验证通过,不管是哪个手指。早期的操作系统版本中可能能够获得是使用的哪个指纹,但是现在一般都不开放了,只能得知指纹集是否发生了变化(删除或者添加了指纹),此时App可以强制用户退出,再使用其它安全的方式登录,然后再让用户决定是否开启指纹,支付宝就是这样做的。
- 重放攻击问题:步骤16中的请求可能被人截获,虽然无法解密,但是可以多次发向服务端,造成重放攻击的问题,可以引入一个挑战码来解决这个问题。步骤8初始化指纹注册请求时服务端可以生成这个挑战码,然后在步骤16中携带这个挑战码,然后在服务端进行验证。
使用指纹认证
下边再来看下使用指纹登录的过程:
- 登录时的本机指纹认证和注册时的本机指纹认证方法相同,只不过这次是在用户选择指纹登录时弹出指纹刷取页面。
- 10签名登录数据:主要是用客户端私钥签名设备的唯一标识和挑战码,在开启指纹认证时指定了必须采用指纹授权的方式才能使用私钥,这样能确保签名是由认证过的用户发起的(准确的说是手机上登录过指纹的所有用户,在开启指纹认证时已经提示用户所有录入的指纹都将可以用来登录,同时如果指纹发生变化,会让用户重新确认,所以可以认为他们都是有权限的用户);服务端如果验证签名通过,则代表数据在传输过程中没有被篡改,登录是在可信的客户端发起的;前后端的认证结果结合起来就代表登录是由认证过的用户发起的。
- 在开启指纹阶段,已经将设备唯一标识、客户端公钥绑定到了用户记录,所以签名验证通过后,就可以生成当前用户的登录Token,并在后续的客户端与服务端的一般交互中使用这个Token。在关键的交互,比如支付中,还是要使用指纹认证这种安全性更高的方式。
以上就是APP中的指纹认证原理,指纹登录和指纹登录的过程差不多,只不过支付需要更高的安全等级,指纹认证可以满足这个安全要求。
客户端身份认证的问题
在上文APP的指纹注册阶段,客户端生成了一对非对称密钥,用于后续服务端认证客户端的身份,这个密钥在当前的手机中已经有了成熟的安全存储和使用方法,这就是TEE(可信执行环境):
客户端私钥被TEE安全密钥加密存储在手机中,目前没有破解之法;同时还可以指定只有通过了本机指纹认证才能使用私钥对数据进行签名和加密;再者如果手机中加入了新的指纹或者删除了指纹,存储的私钥就会失效;所以密钥的存储和使用是可以保证安全的。
但是还存在其它的安全隐患:
1、服务端无法确认上传的客户端公钥能否代表客户端身份,任何程序都可以生成一对非对称密钥,然后对数据进行签名,再把公钥一起发到服务端,服务端仅能验证签名的正确性,但是无法验证公钥的来源,也就无法验证客户端的身份。某些解决方案中会在客户端集成一个认证器SDK,这个SDK生成的认证信息中会携带一些特殊识别信息,而且每个应用每个机器不同,很难破解,后端可以据此判断是在集成了认证器SDK的应用中发起的。但是也有一些难题,识别信息的生成方法可能会被破解,还有怎么确认是用户发起的还是恶意程序发起的?
2、密钥生成过程中可能被黑客替换,存储和使用再怎么安全也无济于事了。这个在微信的技术资料中提到过,Android的密钥生成有被拦截的可能,不确定当前是不是解决了。这也说明底层框架和操作系统也可能是不可信的,在某些场景下必须慎重考虑。
3、以上两个问题在Root或者越狱之后的手机中更严重,APP、SDK和操作系统都无法信任了,所以很多金融类APP不支持在Root或者越狱的手机上使用指纹认证,不过道高一尺魔高一丈,还是有一些方法来欺骗APP,这也不乏部分用户的支持(自作X啊)。
这个问题有好的办法解决吗?有,设备出厂前就把私钥保存到TEE中。
Android中的密钥安全
大家应该知道Android系统是开源的,很多手机厂商都在生产Android手机,市面上有多个厂商在竞争,谁也不服谁,所以要想推广上文提到的出厂前内置私钥的方法,就必须统一标准。在国内腾讯和阿里具备这样的影响力,腾讯搞了SOTER,阿里搞了IFAA,两者都要求手机厂商在产线上生成一对非对称密钥,私钥写入手机TEE,即使拿到了手机当前也没有破解之法,私钥也就不会被泄漏,除非手机厂商搞事情,不过如果手机厂商真的这样做了,就离倒闭不远了;公钥上传到认证服务器,认证的时候用于验证手机APP上传的数据签名,验证通过了就能代表是在对应的手机发起的认证。
同时为了推广这个技术,这种协议还支持别的厂商APP接入进来。但是这样就很容易泄漏APP的商业隐私 ,比如SOTER每次支付都要去腾讯的认证服务器认证一下,据此就可以推断你的业务行为和交易量,所以SOTER又搞了应用密钥和业务密钥,来尽量消除这个商业风险;同时针对Android密钥生成可能被拦截的问题,让手机厂商装个补丁包就解决了,比如替换掉不安全的中间环节。下边来看下应用密钥和业务密钥的产生过程。
应用密钥产生流程:应用密钥在应用首次安装的时候生成,应用密钥的私钥保存在手机端,并使用出厂前内置的私钥签名,然后发到腾讯的认证服务器验证签名,此时应用密钥的公钥会保存到应用的后台。
业务密钥产生流程:在使用登录或者支付的指纹认证注册的时候,应用会再生成一个业务密钥,业务密钥的私钥还是保存在手机端,业务密钥使用手机端的应用密钥进行签名,验证也只需要在应用的后台验证就可以了,此时和腾讯的认证服务器就没有关系了。
这样腾讯就不知道你的实际业务运营情况了,比如每天在线支付多少笔,但是APP安装量还是免不了会暴漏出来,话说APP都要上应用市场的,这个信息其实早就公开了。
关于SOTER详细介绍,可以看官方文档:github.com/Tencent/sot…
IFAA的应用过程和SOTER差不多,这里就不再赘述了。另外国外还有一个FIDO联盟,也是解决这个问题的,国内是联想集团的子公司国民认证在推广这个,技术原理也都差不多。
iOS中的密钥安全
iPhone的操作系统和硬件都是自己控制的,所以对于安全控制它可以做的很好。
对于本机指纹认证,苹果也提供了Touch ID的API,可以在前端调用指纹认证,但是如果要发送到服务端去验证,基于各种安全考虑,就还是需要一个客户端密钥,这个客户端密钥有没有安全的产生方式呢?我没有找到官方的文档说明,很多基于这个方案的第三方应用可能都是自己生成的吧,尽量做到安全。当然这个也是猜测。
但是微信或者支付宝这种应用怎么能忍呢?SOTER曾经说要支持iOS,最后也是不了了之;IFAA宣传的是兼容支持iPhone 5s 以上所有 iOS 手机,不过它不开源。可能苹果最终还是不想把这块放开,同时基于苹果的强势地位,最有可能是苹果专门给这种应用开放了特定的API,不许外传。
如果是做指纹登录,其实可以直接使用苹果开放的Apple ID登录协议,支持指纹和刷脸认证,会给应用返回认证Token和授权码,应用后台拿着这两个再去找苹果验证。从这个逻辑上看,苹果的后台必然能安全的确认发起请求的客户端身份,所以估计和Android的原理差不多,只不过前后端的每次认证都得苹果来验证。
Web中的指纹认证
上面提到过一个FIDO联盟,它和W3C搞了一个WebAuthn标准,它的目的是标准化用户对基于 Web 的应用程序和服务的公钥认证的接口,说人话就是定了一个Web程序中使用公钥认证的标准,所谓的公钥认证就是上文提到的客户端密钥认证技术。这个国内产品好像使用的不多见,不过这件事挺牛的。它可以在Windows、Linux、Mac OS、Android、iOS、智能手表等各种设备中使用指纹识别、面部识别、虹膜识别、声音识别、实体密钥(USB连接、蓝牙连接、NFC连接)等多种方式进行认证,尽可能的摆脱对密码的依赖。
这个技术标准和APP中的公钥认证技术是一脉相承的,主要区别在于APP换成了浏览器,认证模块除了操作系统本身支持,还增加了对专用硬件的支持。有兴趣的可以去了解下。
以上就是本文的主要内容,因能力有限,可能存在部分错漏,欢迎指正。





