1. 程式人生 > >想知道微信怎麽做指紋支付開發?看這裏!

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

剖析 復制。 Go 超過 指紋解鎖 word 服務 完全 man

歡迎大家前往騰訊雲+社區,獲取更多騰訊海量技術實踐幹貨哦~

作者簡介:Henryye,葉軒,來自騰訊微信事業群,主要負責騰訊開源項目TENCENT SOTER(GitHub地址:https://github.com/Tencent/soter )生物認證平臺的開發、維護與運營。

提到指紋支付,你會怎麽做?

假如有一天,產品經理安排你做指紋支付,並且要下版本就上,你會怎麽做?

如果是產品大哥,就從工位下面抽出一把指甲刀架在他脖子上,讓他跪在墻角唱征服;

如果是產品妹子,就讓她請你喝咖啡,然後談天說地,趁此機會告訴她“還是選擇世界和平吧,比做指紋支付簡單多了。”

當然,想象還是太溫柔了。真正做過指紋支付項目的在下,經常會在半夜三更回憶起當年做指紋支付需求時候的噩夢,在夢裏,我就給自己加戲,手撕產品經理。

也許產品大大們會發出抗議:“指紋支付而已,客戶端現成的接口,有何難?”

系統接口行不行?

從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沒有做到什麽呢?

  • 由於沒有一個可信的信任根,導致密鑰很容易被替換;
  • 無法從認證結果中獲取到底是哪一個用戶授權本次認證請求;

同時,我們意識到,在生物認證領域這個千億級市場中,缺乏一個統一、安全、易接入的認證標準,微信有這樣的需求,其他應用也必然如此。微信有能力解決這些問題,實現自己的業務需求,也希望將成功經驗復制。既然這樣,借此機會制定一個生物認證標準,提供一個生物認證平臺,微信責無旁貸,這就是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

技術分享圖片

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