歡迎你們前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~android
做者簡介:Henryye,葉軒,來自騰訊微信事業羣,主要負責騰訊開源項目TENCENT SOTER(GitHub地址:https://github.com/Tencent/soter )生物認證平臺的開發、維護與運營。git
提到指紋支付,你會怎麼作?github
假若有一天,產品經理安排你作指紋支付,而且要下版本就上,你會怎麼作?安全
若是是產品大哥,就從工位下面抽出一把指甲刀架在他脖子上,讓他跪在牆角唱征服;服務器
若是是產品妹子,就讓她請你喝咖啡,而後談天說地,趁此機會告訴她「仍是選擇世界和平吧,比作指紋支付簡單多了。」微信
固然,想象仍是太溫柔了。真正作過指紋支付項目的在下,常常會在半夜三更回憶起當年作指紋支付需求時候的噩夢,在夢裏,我就給本身加戲,手撕產品經理。架構
也許產品大大們會發出抗議:「指紋支付而已,客戶端現成的接口,有何難?」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