想知道微信怎麼作指紋支付開發?看這裏!

歡迎你們前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~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百密一疏:若是黑客在密鑰生成的時候就攔截了請求,替換爲本身的密鑰,那麼後面簽名和加密,用的也是黑客的密鑰,那麼整套系統的設計也就崩塌了。

Hack示意

另外還有一個問題,若是僅僅返回true/false,那麼只要是錄入到設備內的指紋,就能夠假冒你的身份支付。這對於家裏有熊孩子的家長來講,簡直就是銀行卡噩夢。雪上加霜的是,對於Android設備而言(其實iOS也是同樣),只要知道了鎖屏密碼就能夠錄入新的指紋。若是支付後臺直接信任指紋認證結果,就至關於將本來很是祕密的支付密碼,退化到了鎖屏密碼的級別。這樣,不管支付後臺作了多麼嚴密的風控策略,按照木桶原理,從根本上整個系統就是不符合支付安全的。

固然,當時也有相似於FIDO(連接:https://fidoalliance.org/)之類的認證聯盟,可是整個流程過於複雜,甚至還要求在應用後臺植入sdk。並且,相似方案的中心服務權限太高,會致使如支付筆數、開通用戶數等關鍵指標爲人所知,所以也就沒法使用。而且支持設備數實在太少,也並沒有接入動力。

研究過這些以後,發現並不可直接使用任何一個方案,場面一度尷尬。沒有合適的輪子,怎麼辦?

沒有輪子,能造輪子麼?

讓咱們回頭看看Android系統的指紋接口設計:

  • 方便的指紋接口,完美!
  • 創造性得將指紋模塊與密鑰模塊結合起來,使得用戶受權即簽名變得可能,完美!

那Google沒有作到什麼呢?

  • 因爲沒有一個可信的信任根,致使密鑰很容易被替換;
  • 沒法從認證結果中獲取究竟是哪個用戶受權本次認證請求;

同時,咱們意識到,在生物認證領域這個千億級市場中,缺少一個統1、安全、易接入的認證標準,微信有這樣的需求,其餘應用也必然如此。微信有能力解決這些問題,實現本身的業務需求,也但願將成功經驗複製。既然這樣,藉此機會制定一個生物認證標準,提供一個生物認證平臺,微信義不容辭,這就是SOTER的起源。

若是以作標準的要求來實現SOTER,那麼除了剛剛所述的系統接口缺陷以外,系統設計時還須要考慮:

  • 後臺不存儲任何敏感信息,包括對稱密鑰、非對稱密鑰私鑰,更不能將用戶生態無特徵(如指紋圖案)以任何形式傳輸或存儲,防止應用後臺被脫庫;
  • 若是有後臺交互,不暴露應用方核心商業隱私,如認證次數、業務開通次數;
  • 應用接入門檻低,客戶端無須集成重量級sdk,後臺無須集成sdk;
  • 簡單易用,第三方應用只須要操做上層接口,無須進行復雜的底層開發。

如何產生一個可信的信任根(設備根密鑰)?

信任根的重要性以前已經說明。若是一個系統依賴密鑰簽名,有一個能夠信任的根密鑰,纔有可能構建安全的信任模型。可是,若是一臺手機出廠以後才產生根密鑰(ATTK),那麼中間有足夠時間窗口給到黑產從業者替換掉它。所以,常規方式產生根密鑰必定是不行的。因此,咱們有了一個大膽的想法:直接與廠商合做,在設備出廠以前,產線上生成設備根密鑰,公鑰經過廠商服務傳輸給微信密鑰服務——TAM。這個想法雖然對廠商改造比較大,可是因爲咱們直接通產業鏈上游(高通、MTK等)合做,研發出了一套統一的解決方案,以及產線工具,成功說服廠商對產線作了最小化的改造。It’s tough, but we did it!

設備根密鑰流程

  1. 廠商在產線上對設備下發生成設備根密鑰命令;
  2. TEE中生成一對設備惟一的RSA-2048非對稱密鑰,私鑰存儲在設備RPMB區域,沒有任何廠商或者應用方能夠讀取(包括微信與設備廠商),公鑰以及設備ID導出;
  3. 公鑰和設備ID上傳到廠商服務器,以後經過公衆平臺安全接口,傳輸到微信公衆平臺;
  4. 微信公衆平臺將公鑰與設備ID傳輸到微信TAM服務器。

這裏,咱們又遇到了咱們的老朋友: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. 應用第一次啓動時,或者在第一次使用業務以前,請求生成設備根密鑰;
  2. 密鑰生成以後,私鑰在被TEE保護,加密存儲;
  3. 公鑰和設備ID等相關信息,在TEE內直接被設備密鑰私鑰簽名以後,返回給應用;
  4. 應用將公鑰相關信息和簽名傳輸至應用後臺;
  5. 應用後臺經過微信公衆平臺後臺接口,請求驗籤;
  6. TAM使用對應的設備密鑰公鑰驗籤,經過以後返回給應用;
  7. 應用後臺存儲對應的應用公鑰。

傳輸給後臺的原串示例:

注1:自設備出廠即在TEE中存儲。每一次SOTER相關操做都會使該值自增,後臺存儲該放重放因子。若是後臺發現本次請求防重放因子比已記錄的值小,則可認爲是非法請求。

注2:本意爲類Unix系統中用戶ID,在Android系統中,通常而言每個應用都有一個uid,可用於區分應用以及權限控制。注意,uid不一樣,對應的應用密鑰與業務密鑰均不一樣,後臺應將uid與cpu_id一塊兒區分密鑰。

準備業務密鑰(Auth Key)

準備業務密鑰流程示意圖

  1. 應用在開通業務時(如指紋支付),請求生成業務密鑰。同時,在生成時聲明該密鑰除非用戶指紋受權,不然私鑰不可以使用。
  2. 密鑰生成以後,私鑰在被TEE保護,加密存儲;
  3. 公鑰和設備ID等相關信息,在TEE內直接被應用密鑰私鑰簽名以後,返回給應用;
  4. 應用將公鑰相關信息和簽名傳輸至應用後臺;
  5. 應用後臺使用對應的應用密鑰公鑰驗籤,無須請求微信TAM中心服務;
  6. 驗籤成功以後,應用後臺存儲對應的業務密鑰。

傳輸數據與含義與應用密鑰相同,再也不贅述。

認證流程

認證流程示意圖

  1. 客戶端請求後臺,獲取挑戰因子;
  2. 獲取挑戰因子以後,將挑戰因子送往TEE,準備簽名結構體,準備簽名;
  3. 應用請求用戶指紋受權;
  4. 用戶指紋受權後,直接將本次認證使用指紋在本設備內的索引傳輸給密鑰模塊,在TEE內使用業務密鑰私鑰簽名挑戰因子以及該索引。

應用獲取原串與簽名串後,傳輸至應用後臺。應用後臺使用對應的業務密鑰公鑰驗籤,若是成功,則這次認證或者開通請求合法。

傳輸給後臺原串示例

流程是否符合要求?

輪子造好了,咱們在自我欣賞的路上越走越遠。回過頭來看,SOTER是否知足了咱們的要求呢?

  • 添加信任根:SOTER在工廠環境中傳輸設備根密鑰,保證信任根安全;
  • 可區分指紋:認證以後,TEE內部直接傳輸本次使用的指紋ID,可以使應用自由選擇是否區分指紋;
  • 後臺不存儲敏感信息:後臺僅存儲設備ID和公鑰,今後即便後臺設計再爛,也再也不懼怕脫庫;
  • 後臺交互不暴露隱私:首創應用密鑰,保證業務開通、業務使用量等不須要通過應用服務器;
  • 後臺不須要sdk:後臺使用成熟的公衆平臺接口,文檔豐富,學習成本低,更無須sdk。

固然了,咱們的方案獲得了各大廠商、芯片上的承認,在短期內,已經擁有了數億設備的支持,覆蓋幾乎全部的主流手機品牌,所以應用接入徹底無須考慮是否須要多設備適配,或者質疑適配不足。順便,咱們支持了vivo和OPPO的5.x指紋機型,即便系統自己不具備統一的指紋接口。

然而,還有最後兩點沒有作到:

  • 客戶端接入門檻低,客戶端sdk輕量,甚至不須要sdk;
  • 簡單易用,客戶端無須進行深度開發便可使用。

解決這兩個問題的方法只有:開源!

咱們開源了什麼?

爲了知足不一樣應用的不一樣場景,咱們開源了:

  • SOTER客戶端核心接口soter-core:SOTER內部操做密鑰、調用指紋的直接接口。sdk大小約40KB,對安裝包大小增量可忽略不計;
  • SOTER客戶端過程封裝接口soter-wrapper:封裝了SOTER具體流程以及適配問題機型。sdk大小約70KB,安裝包大小增量更少;
  • 快速上手的客戶端demo,從零開始,幫你短短几行代碼實現指紋支付;
  • 完整的客戶端文檔和後臺接口文檔;
  • 完整的原理剖析和快速入手。

這一切,盡在TENCENT SOTER(GitHub地址:https://github.com/Tencent/soter,點擊 閱讀全文 亦可直接訪問)。

使用SOTER最快能多塊?若是你只須要作鎖屏之類對安全性要求不高的需求,只須要:

  • 添加gradle依賴

在項目的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

相關文章
相關標籤/搜索