欢迎你们前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~
android
做者简介:Henryye,叶轩,来自腾讯微信事业群,主要负责腾讯开源项目TENCENT SOTER(GitHub地址:https://github.com/Tencent/soter )生物认证平台的开发、维护与运营。git
提到指纹支付,你会怎么作?github
假若有一天,产品经理安排你作指纹支付,而且要下版本就上,你会怎么作?安全
若是是产品大哥,就从工位下面抽出一把指甲刀架在他脖子上,让他跪在墙角唱征服;bash
若是是产品妹子,就让她请你喝咖啡,而后谈天说地,趁此机会告诉她“仍是选择世界和平吧,比作指纹支付简单多了。”服务器
固然,想象仍是太温柔了。真正作过指纹支付项目的在下,常常会在半夜三更回忆起当年作指纹支付需求时候的噩梦,在梦里,我就给本身加戏,手撕产品经理。微信
也许产品大大们会发出抗议:“指纹支付而已,客户端现成的接口,有何难?”架构
系统接口行不行?app
从2013年iPhone 5s第一款带有指纹识别功能的iPhone上市以来,“指纹支付”这个词就开始频繁出如今各个产品的PM列表排期中。可是,Android 6.0之前的设备,并无一个统一的指纹认证接口。这也就意味着若是你是一个苦逼的程序猿,那么你就要一家家适配各自的指纹方案,而且还要维护厂商的接口升级。若是结合Android市场的碎片化来看,想要全机型覆盖,简直就是Impossible Mission。实际上,在项目初期,微信便尝试了一家家接入,结果仅仅接入华为Mate 7和荣耀7,便用了整整三个月!这种投入显然是得不偿失的。微信公众平台
好在,从Android 6.0开始,系统提供了标准的FingerprintManager。这一重大利好,让作着相似需求的程序猿们仿佛在黑暗中看到一丝光明,由于这个接口看上去是那么简单易用。不管你是什么品牌的手机,只要是Android 6.0或更新的系统,按照下面的写法,就能够实现指纹认证功能:
FingeprintManager mFingeprintManager = ...
mFingeprintManager.authenticate(null,
mCancellationSignal, 0 , new AuthenticationCallback(){...},
null);
复制代码
系统认证接口
看上去很完美,仿佛实现指纹支付根本不用开发1个版本,只用1小时,对不对!
可是仔细看下这个接口,感受哪里不太对:接口仅仅返回认证成功/失败,若是直接信任这个结果,手机被root了,岂不是随时能够将认证结果从false改成true?
那咱们换一种思路:root的手机不让用指纹支付行不行?
傻孩子,那你怎么判断手机是否是root呢?不也是经过Android接口获取的值么?这个值同样能够被改掉。
支付安全不可儿戏,一旦出问题,就是重大事故。所幸的是,Google也意识到了这个问题,因此在发布指纹认证接口的同时,加强了本来的KeyStore接口,和Fingeprprint接口联动(代码实现可参考Google官方Sample,连接:https://github.com/googlesamples/android-FingerprintDialog):
这张图看上去不明觉厉,原理其实并不难:Google在Android 6.0以后,容许用户在应用中生成一对非对称密钥,将私钥存储在TEE中(什么是TEE?稍后会讲),任何人,包括应用本身甚至Android系统都没法获取私钥,除非用户使用指纹受权才能使用,签名或者加密传入的数据,而后输出密文。这样的话,就能够利用密钥的签名-验签机制(小白不懂什么是签名验签?Google下咯~或者看这篇文章解释签名的部分),只有用户使用指纹签名以后,才能产生正确的签名,后台验签便可,这样就能保证链路安全。
这个设计很是巧妙,可是Google百密一疏:若是黑客在密钥生成的时候就拦截了请求,替换为本身的密钥,那么后面签名和加密,用的也是黑客的密钥,那么整套系统的设计也就崩塌了。
另外还有一个问题,若是仅仅返回true/false,那么只要是录入到设备内的指纹,就能够假冒你的身份支付。这对于家里有熊孩子的家长来讲,简直就是银行卡噩梦。雪上加霜的是,对于Android设备而言(其实iOS也是同样),只要知道了锁屏密码就能够录入新的指纹。若是支付后台直接信任指纹认证结果,就至关于将本来很是秘密的支付密码,退化到了锁屏密码的级别。这样,不管支付后台作了多么严密的风控策略,按照木桶原理,从根本上整个系统就是不符合支付安全的。
固然,当时也有相似于FIDO(连接:https://fidoalliance.org/)之类的认证联盟,可是整个流程过于复杂,甚至还要求在应用后台植入sdk。并且,相似方案的中心服务权限太高,会致使如支付笔数、开通用户数等关键指标为人所知,所以也就没法使用。而且支持设备数实在太少,也并没有接入动力。
研究过这些以后,发现并不可直接使用任何一个方案,场面一度尴尬。没有合适的轮子,怎么办?
没有轮子,能造轮子么?
让咱们回头看看Android系统的指纹接口设计:
那Google没有作到什么呢?
同时,咱们意识到,在生物认证领域这个千亿级市场中,缺少一个统1、安全、易接入的认证标准,微信有这样的需求,其余应用也必然如此。微信有能力解决这些问题,实现本身的业务需求,也但愿将成功经验复制。既然这样,借此机会制定一个生物认证标准,提供一个生物认证平台,微信义不容辞,这就是SOTER的起源。
若是以作标准的要求来实现SOTER,那么除了刚刚所述的系统接口缺陷以外,系统设计时还须要考虑:
如何产生一个可信的信任根(设备根密钥)?
信任根的重要性以前已经说明。若是一个系统依赖密钥签名,有一个能够信任的根密钥,才有可能构建安全的信任模型。可是,若是一台手机出厂以后才产生根密钥(ATTK),那么中间有足够时间窗口给到黑产从业者替换掉它。所以,常规方式产生根密钥必定是不行的。因此,咱们有了一个大胆的想法:直接与厂商合做,在设备出厂以前,产线上生成设备根密钥,公钥经过厂商服务传输给微信密钥服务——TAM。这个想法虽然对厂商改造比较大,可是因为咱们直接通产业链上游(高通、MTK等)合做,研发出了一套统一的解决方案,以及产线工具,成功说服厂商对产线作了最小化的改造。It’s tough, but we did it!
设备根密钥流程
这里,咱们又遇到了咱们的老朋友:TEE(Trusted Execution Environment),后面咱们也会屡次与这个名词打交道。若是想要看详细的介绍,能够参考这里(连接:https://en.wikipedia.org/wiki/Trusted_execution_environment)。固然了,我相信大部分同窗都跟我同样,只想要一个形象的解释。简单地说,你的手机中,除了相似Android这样的操做系统以外,还有一个独立的环境。这个环境目前并没有行之有效的破解方法,也就是说即便Root了Android系统,都没法破解TEE中的数据。若是将整部手机比做房子的话,Android操做环境就是客厅,TEE就是你的保险箱。可想而知,若是将全部的数据都存储在TEE,关键操做也在TEE内进行,岂不美哉!固然了,这样的话,全部从TEE中出来的敏感数据,就必定要添加上使用可信密钥对其的签名了。
有了设备根密钥以后,认证链的构造逻辑就清晰了不少:采用密钥链的形式,用已认证的密钥来认证未认证的密钥就能够了!
如何构造完整认证流程?
方法论有了,实施就变得简单。
可是,依然有一个问题须要思考:到底须要多少层密钥呢?密钥层数少,那么每一次都须要前往中心服务(微信TAM)验签,对第三方应用而言,会更担忧泄露本身的商业逻辑;密钥层数越多,会增长了传输复杂度和失败率。通过多方讨论,SOTER决定使用三级密钥,除了产线预制的设备根密钥以外,增长定义应用密钥(每个应用生命周期内只须要存在一对)和业务密钥(每个业务须要一对)。事实证实,这是一个明智的选择:这样既保证了流程的流畅度,又保证应用的关键商业隐私不暴露。为何?往下看。
架构
SOTER架构图
咱们十分欣赏Google的指纹和密钥模块接口设计,所以,咱们与厂商合做,在此基础上添加patch包,便可迅速实现整个上层架构。
准备应用密钥(ASK)
准备应用密钥流程示意图
传输给后台的原串示例:
注1:自设备出厂即在TEE中存储。每一次SOTER相关操做都会使该值自增,后台存储该放重放因子。若是后台发现本次请求防重放因子比已记录的值小,则可认为是非法请求。
注2:本意为类Unix系统中用户ID,在Android系统中,通常而言每个应用都有一个uid,可用于区分应用以及权限控制。注意,uid不一样,对应的应用密钥与业务密钥均不一样,后台应将uid与cpu_id一块儿区分密钥。
准备业务密钥(Auth Key)
准备业务密钥流程示意图
传输数据与含义与应用密钥相同,再也不赘述。
认证流程
认证流程示意图
应用获取原串与签名串后,传输至应用后台。应用后台使用对应的业务密钥公钥验签,若是成功,则这次认证或者开通请求合法。
传输给后台原串示例
流程是否符合要求?
轮子造好了,咱们在自我欣赏的路上越走越远。回过头来看,SOTER是否知足了咱们的要求呢?
固然了,咱们的方案获得了各大厂商、芯片上的承认,在短期内,已经拥有了数亿设备的支持,覆盖几乎全部的主流手机品牌,所以应用接入彻底无须考虑是否须要多设备适配,或者质疑适配不足。顺便,咱们支持了vivo和OPPO的5.x指纹机型,即便系统自己不具备统一的指纹接口。
然而,还有最后两点没有作到:
解决这两个问题的方法只有:开源!
咱们开源了什么?
为了知足不一样应用的不一样场景,咱们开源了:
这一切,尽在TENCENT SOTER(GitHub地址:https://github.com/Tencent/soter,点击 阅读全文 亦可直接访问)。
使用SOTER最快能多块?若是你只须要作锁屏之类对安全性要求不高的需求,只须要:
在项目的build.gradle中,添加 SOTER依赖
dependencies {
...
compile 'com.tencent.soter:soter-wrapper:1.3.8'
...
}复制代码
在 AndroidManifest.xml中添加使用指纹权限
<uses-permission
android:name="android.permission.USE_FINGERPRINT"/>复制代码
初始化过程整个应用声明周期内只须要进行一次,用于生成基本配置和检查设备支持状况。你能够选择在Application的onCreate()中,或者在使用SOTER以前进行初始化。
InitializeParam param = new InitializeParam.InitializeParamBuilder()
.setScenes(0) // 场景值常量,后续使用该常量进行密钥生成或指纹认证
.build();
SoterWrapperApi.init(context, new
SoterProcessCallback<SoterProcessNoExtResult>() {...},
param);复制代码
须要在使用指纹认证以前生成相关密钥
SoterWrapperApi.prepareAuthKey(new
SoterProcessCallback<SoterProcessKeyPreparationResult
>() {...},false, true, 0, null, null);复制代码
密钥生成完毕以后,可使用封装接口调用指纹传感器进行认证。
AuthenticationParam param = new AuthenticationParam.AuthenticationParamBuilder()
.setScene(0)
.setContext(MainActivity.this)
.setFingerprintCanceller(mSoterFingerprintCanceller)
.setPrefilledChallenge("test challenge")
.setSoterFingerprintStateCallback(new
SoterFingerprintStateCallback() {...}).build();
SoterWrapperApi.requestAuthorizeAndSign(new
SoterProcessCallback<SoterProcessAuthenticationResult>
() {...}, param);复制代码
固然了,若是你想要实现指纹支付、指纹登陆等高安全性场景,还有一些其余工做要作,具体能够参考咱们的示例代码(连接:https://github.com/Tencent/soter/tree/master/soter-client-demo)和安全接入文档(连接:https://github.com/Tencent/soter/wiki/%E5%AE%89%E5%85%A8%E6%8E%A5%E5%85%A5)。
SOTER(GitHub地址:https://github.com/Tencent/soter) 开源以后,已经有包括微众银行在内的多个应用已经接入,这些应用接入的时间均不超过一个版本。使用的场景也从指纹支付,到指纹登陆、指纹解锁。用过的,都说好。
那么,让咱们再回顾下开头的场景:“咱们要作指纹支付,下个版本上…”,想必你已经知道怎么作了,括弧逃~
问答
相关阅读
此文已由做者受权腾讯云+社区发布,转载请注明文章出处
原文连接:https://cloud.tencent.com/developer/article/1031094?fromSource=waitui