導讀
introduction
百度小程式已經在百度開源聯盟的多家宿主APP上運作,為了保證小程式架構、小程式、宿主APP等業務方互相之間的通信服務不被惡意攻擊,營運類活動不被薅羊毛,基于最新的TLS1.3的協定标準,百度小程式研發團隊推出了一套安全防固多APP、多業務的百度安全通信協定方案。下面将從握手到加密業務傳輸各個階段,介紹相關算法、技術選型、Server與Client的實作方案。
全文9260字,預計閱讀時間24分鐘。
GEEK TALK
01
前言
随着移動網際網路的高速發展,智能手機的全面普及,各式各樣的APP出現,友善了人們的生活,同時也帶來了巨大的安全風險。APP主要面臨的風險:
- 靜态攻擊:APP被反編譯分析源碼後,被破解、篡改、二次打包、仿冒/釣魚等攻擊手段;
- 動态攻擊:APP在運作期,使用者操作行為不可控,通過模拟器、多開器、加速器、注入攻擊、動态調試(抓包)、裝置篡改、位置欺詐等攻擊手段;
- 業務作弊:黑産使用者通常在APP注冊、登入、營運活動、頁面爬蟲等場景進行批量化、機器化的一些手段操作;
面對以上這些攻擊手段,最終第三方會通過網絡騙取到伺服器的信任,竊取一些有效資訊,最後威脅平台和使用者的利益,是以,網絡通信安全的意識也受到各方關注。國内外的網絡服務提供商逐漸提供了全站的安全通信服務,如蘋果公司在2017年1月1日要求所有提審的APP必須啟用App Transport Security(ATS)安全功能,強制使用HTTPS,否則無法通過稽核;國内主流大廠百度、阿裡、騰訊等,已經全站部署HTTPS。雖然有了HTTPS的加持,但是并不意味着網絡通信就安全,常見的加密通信協定都在業務層,包體加密、標頭明文,這樣通過抓包方式還是能擷取到明文的請求頭、傳回資料。百度智能小程式的開源方案已經在多個開源宿主APP上落地(比如:愛奇藝、小紅書、百度地圖等),為了保證百度智能小程式在每個宿主APP上通信安全,需要一套小程式的請求從Client到Server端資料全程加密保護,于是誕生出 bdtls。
GEEK TALK
02
目标
基于百度智能小程式自身業務特點,涉及到小程式開發者、宿主APP開發者、小程式架構開發者多方參與(後續非小程式業務場景),在安全性、性能和可用性等名額上存在互相影響,是以設計出來的安全協定必須滿足以下幾點:
- 安全性:支援雙向認證,通信内容加密;支援前向安全,若發生密鑰洩露,也不能破解出曆史請求的資料;
- 低延遲:足夠高的性能,對内容的加解密性能損耗要小于請求整體耗時10%;
- 可用性:支援分級(分業務、宿主)降級服務、快速恢複服務;
- 可擴充:支援業務分級通信、支援分App認證、協定更新(可替換安全等級更高的密碼套件);
通過分析業界公開的安全通信協定--TLS(在2018年前,正式最高版本為1.2),發現在安全、性能等方面已經跟不上如今的網際網路時代,在建立握手連接配接過程中需要2-RTT,導緻額外的網絡延遲;同時,TLS1.2還存在許多不安全的加密算法:
- 僞随機數函數PRF;
- RC4、DES 對稱加密算法;
- ECB、CBC 等傳統分組模式;
- MD5、SHA1、SHA-224 摘要算法;
- RSA、DH 密鑰交換算法和許多命名曲線;
- 記錄協定裡使用壓縮算法;
對比即将釋出的TLS1.3協定有三個主要的改進目标:相容、安全、性能,正好滿足我們的需求,于是我們基于TLS1.3的草案标準,設計了百度自己的安全通信協定-- bdtls。
GEEK TALK
03
bdtls 協定設計
3.1 總體架構
bdtls 協定的實作參考 TLS1.3 協定規範,不依賴某個特定的網絡傳輸協定。不同的是,TLS 過程處于傳輸層和網絡層之間,對傳輸層的資料進行加密,而 bdtls 處于應用層和傳輸層之間,對應用層資料進行加密,不影響原有的網絡政策。bdtls 架構主要分兩部分功能:握手(握手階段)和加密資料傳輸(業務階段),這兩部都是基于以下協定完成雙方通信。
3.2 協定介紹
借鑒TLS1.3的設計原理,精簡了部分子協定及字段,保留了Record、Handshake、Application、Alert四個協定,下面是這些協定之間的關系如下圖:
- Handshake協定:握手協定,用于Client 和 網關Server之間的握手階段,協商 bdtls 版本号、随機數、密碼套件等資訊,然後交換證書和密鑰參數,最終雙方協商得到會話密鑰,用于後續的混合加密系統;
- Application協定:應用協定,用于Client 和 業務Server之間的業務階段,在加密資料傳輸階段,構造加密傳輸資料、解析response的加密業務資料,是Record協定的上層協定;
- Alert協定:警報協定,用于握手階段、業務階段,Server以提醒、錯誤方式通知到Client端,進行關閉連接配接、降級、恢複等操作;
- Record協定:記錄協定,規定了 TLS 收發資料的基本機關:記錄(record)。用于握手階段、業務階段,負責資料的發送,資料分割、壓縮、加密,然後發給底層的協定(TCP)進行處理;接收方對資料解密、校驗、解壓、聚合,再發給上層的協定(Handshake、Application、Alert);
結合以上協定,下面是bdtls握手階段和加密資料傳輸階段的過程圖:
對比TLS1.2握手協商階段,密碼套件大幅度簡化,壓縮了“Hello”協商過程,删除了“Key Exchange”消息,将握手時間減少“1-RTT”(消息往返),效率提升一倍。bdtls在Handshake協定加入擴充實作了TLS1.3裡面标準的“1-RTT”握手,用戶端在“Client Hello”消息裡直接用“supported_groups”帶上支援的曲線,比如 P-256、x25519,用“key_share”帶上曲線對應的用戶端公鑰參數,用“signature_algorithms”帶上簽名算法。伺服器收到後在這些擴充裡標明一個曲線和參數,再用“key_share”擴充傳回伺服器這邊的公鑰參數,就實作了雙方的密鑰交換。
TLS1.3 還引入了“0-RTT”握手,利用“pre_shared_key”和“early_data”擴充,在 TCP 連接配接後立即就建立安全連接配接發送加密消息,不過“0-RTT”的實作依賴長期儲存的密鑰ticket_key,如果ticket_key洩露,那麼加密的資料就不太安全了,是以“0-RTT”密鑰協商過程中,需要提高前向安全性,本次不再詳細贅述,bdtls結合自身業務的需要,僅提供“1-RTT”握手。
3.2.1 Handshake協定
Handshake協定主要工作就是用于Client和Server握手協商,協商出一個對稱加密密鑰 Key 以及其他密碼材料為後面的資料加密傳輸做準備。要實作安全的握手,這裡需要注意兩個問題:
- 問題1:如何安全地進行密鑰交換?
- 問題2:如何防止密鑰資訊被僞造?
第一個問題涉及密鑰如何傳輸,需要用到密鑰交換算法;第二個問題涉及密鑰資訊被僞造、篡改,資訊是否完整,需要用到數字簽名算法。這在TLS1.3裡提供了多種密鑰交換和數字簽名算法,我們可以根據自己的業務訴求和實作成本選擇合适的算法。
問題1解答:對于密鑰交換的問題,隻能選擇非對稱加密算法,TLS提供密鑰協商算法有:DH、ECDH、RSA、ECC、PFS方式的(DHE、ECDHE)等,bdtls選擇DHE算法,它的核心是取模運算,具有單向不可逆性,資料“前向安全”,關鍵在于“E”表示的臨時性(ephemeral),每次交換密鑰時雙方的私鑰都是随機選擇、臨時生成的,用完就扔掉,下次通信不會再使用,相當于“一次一密”。是以,即使攻擊者破解了某一次的私鑰,其他通信過程的私鑰仍然是安全的,不會被解密,實作了“前向安全”。有沒有比 DHE 速度更快,可逆難度更難的算法嗎?ECDHE,基于ECC和DHE基礎上進行組合,就是把 DHE 算法裡整數域的離散對數,替換成了橢圓曲線上的離散對數,這種橢圓曲線離散對數的計算難度比普通的離散對數更大,是以 ECDHE 的安全性比 DHE 還要高,更能夠抵禦黑客的攻擊。但是基于百度智能小程式當時的業務,選擇了實作成本較低的DHE算法,後面密鑰交換會逐漸更新成ECDHE。下面簡單介紹DH算法基礎實作:
明白了以上模運算的交換流程,我們就能知道它是怎麼用來傳遞鑰匙的了,過程如下:
- Alice和Bob兩人共同約定底數G、模數P(G、P要求是質數,比如:G = 5、P = 17),這兩個數是公開的;
- Alice随便選擇一個整數A(比如:A = 10),鮑Bob也随便選擇一個整數B(比如:B = 5),他們随機選擇整數作為私鑰,這兩個數是嚴格保密的;
- 有了DH的私鑰,Alice通過函數:G ^ A % P 計算幂α(α = 9),Bob通過函數:G ^ B % P 計算幂β(β = 14),各自計算出來的幂作為公鑰,這兩個數是可以公開的,因為根據離散對數的原理,從真數反向計算對數 a 和 b 是非常困難的;
- Alice和Bob互相交換各自的DH 公鑰α、β;
- Alice通過函數:β ^ A % P,計算出共享密鑰K(K = 8),Bob通過函數:α ^ B % P計算出共享密鑰K(K = 8);
- 最後Alice和Bob分别計算完後,得到相同的數字,這個結果就可以當作他們之間的鑰匙。整個通信過程沒人傳遞過鑰匙,但雙方都拿到了同樣的鑰匙。對竊聽者來說,隻偷聽到的DH 公鑰,因為這種運算是不可逆的,是以竊聽者也白聽。這個鑰匙叫會話密鑰,雙方的共享密鑰,也就是TLS裡面的Pre-Master。
小結:bdtls密鑰協商算法套件:DHE,協商出共享密鑰。
問題2解答:通過DHE算法得到的共享密鑰,并不能讓Client和Server雙方安全通信,攻擊者可以在密鑰交換前冒充對Client,與Server分别完成密鑰交換,并進行正常的認證加密通信,這時通信雙方可能是難以察覺的,這就帶來了資料洩露、被篡改的風險,這種攻擊稱為中間人攻擊(Man-In-The-Middle attack),是需要對密鑰資訊進行認證。目前對消息認證有兩種方式:基于消息認證碼(Message Authentication Code)的對稱認證(簡稱MAC)和基于數字簽名的非對稱認證,消息認證碼無法防止否認,存在密鑰配送問題,而數字簽名具有防止否認特性,不存在密鑰配送問題,這樣數字簽名與密鑰協商搭配更合适,常用的數字簽名算法有:RSA、ELGamal、DSA、ECDSA等,在bdtls中采用數字簽名算法為RSA,下面是RSA簽名與驗簽的流程:
一般來說身份認證是需要互相驗證,但在實際的通信過程中,隻要保證通信一方簽名的協商資料不被中間人攻擊就可以了,bdtls隻對Client做認證。上面将密鑰協商(DHE)與數字簽名(RSA)結合起來,實作了一套帶認證的密鑰協商方案:
握手前的工作:
- 首先由Server生成RSA的公私鑰對(rsa_publickey、rsa_privatekey);
- Server将RSA公鑰(rsa_publickey)發送給Client,私鑰(rsa_privatekey)自己保留;
- Client通過DHE算法,生成協商前的DH私鑰(client_dhe_privatekey)、公鑰(client_dhe_publickey)、加密公鑰(client_encrypt_dhe_publickey:RSA加密生成)。
握手中的工作:
- Server接收到Client的加密後DH公鑰(client_encrypt_dhe_publickey),RSA解密出client_dhe_publickey;
- Server通過DHE算法,生成協商前的DH私鑰(server_dhe_privatekey)、公鑰(server_dhe_publickey)、加密公鑰(server_encrypt_dhe_publickey:RSA加密生成);
- Server将client_dhe_publickey與server_dhe_privatekey協商後,得到共享密鑰master_secret,是Server進行業務加解密所需要的對稱密鑰;
- Server再将master_secret通過AES算法,得到加密後的skr,Server在業務階段解密出skr,得到master_secret;
- Server将server_encrypt_dhe_publickey進行hash後,通過RSA的私鑰進行簽名。
握手後的工作:
- Client解密出Server協商後的server_dhe_publickey;
- Client将server_dhe_publickey進行hash後,通過RSA的公鑰進行簽名;
- 驗簽通過後,将server_dhe_publickey與client_dhe_privatekey協商後,得到共享密鑰master_secret,是Client進行業務加解密所需要的對稱密鑰;
- 驗簽不通過,握手請求中斷,業務請求失敗。
小結:bdtls數字簽名算法套件:RSA,私鑰簽名,公鑰驗簽。
3.2.2 Alert協定
Alert用來通知對方本次資料互動中出現的問題,協定參照TLS協定,分為warning和fatal兩個錯誤級别。
服務端的Alert傳回包含兩類:
- 服務端對用戶端目前會話周期不信任,此時用戶端應重新發起握手,交換新的加密密鑰。
- 服務端對用戶端身份不信任,用戶端應該直接報錯,不再嘗試重新握手。
3.2.3 Application協定
握手完成後,需要Client與業務Server通信,将業務資料輸入到record層,進行分段、MAC、加密操作。通過抓包工具,資料格式如下:
http(https)的body請求體裡是密文,response裡也是密文,通過協商共享密鑰将整個傳輸内容全部加密,對于第三方的攻擊完全黑盒。業務傳輸過程中,由于非對稱加密算法效率比對稱加密算法的要低,影響網絡傳輸,是以業務傳輸使用的加密算法一般選擇對稱算法。TLS 裡有非常多的對稱加密算法可供選擇,比如:RC4、DES、3DES、AES、ChaCha20 等,但前三種算法都被認為是不安全的,通常都禁止使用,目前TLS1.3提供的隻有 AES 和 ChaCha20。AES 是“進階加密标準”(Advanced Encryption Standard),密鑰長度可以是 128、192 或 256。它是 DES 算法的替代者,安全強度很高,性能也很好,而且有的硬體還會做特殊優化,是以非常流行,是應用最廣泛的對稱加密算法。ChaCha20 是 Google 設計的另一種加密算法,密鑰長度固定為 256 位,優勢沒有AES明顯。bdtls加密算法選擇AES,分組密碼選擇GCM。
對于資料完整性校驗,需要用到Hash雜湊演算法,常見的Hash雜湊演算法有:MD5、SHA-0、SHA-1、SHA-2、SHA-3,MD5、SHA-0、SHA-1這三個已經不安全了,比較常用的是SHA-2家族的SHA-256、SHA-512,還未被攻破,SHA-3釋出比較晚,普及比較慢。bdtls資料完整性校驗算法選擇SHA-256。
小結:根據對稱加密與完整性校驗算法的性能對比,bdtls業務層使用加密與完整性算法套件:AES-128-GCM-SHA256。
GEEK TALK
04
實作方案
4.1 Sever端實作方案
服務端的實作方案分為兩個部分:握手服務和加解密服務。
4.1.1 握手服務
握手階段主要解決問題是安全的協商出一份密鑰,協商部分的機制和流程可以參考 “3.2.1 Handshake協定” 。除此之外,握手服務在做了以下三件事情:
- 宿主身份校驗
- 包簽名校驗
- 業務方校驗
首先,宿主身份校驗。bdtls 不僅支援手百宿主,還支援所有開源聯盟中的宿主,如愛奇藝、小紅書甚至 oppo、vivo 浏覽器等。如何安全和多個宿主進行握手同時防止宿主私下裡交換密鑰資訊,是這一步需要考慮的問題。我們的解決方案是對不同的宿主簽發不同的密鑰對,并在協定中增加宿主身份辨別,通過身份辨別解決密鑰對的比對問題,并在握完手之後生成的 skr 中寫入宿主身份資訊。在後續的業務請求階段,會再次校驗 skr 的宿主身份資訊和請求資料中的宿主身份資訊是否比對。通過以上的一整套流程,就完成了對宿主身份的校驗。
然後,包簽名校驗。在實際使用中,我們發現一個宿主可能會衍生出不同的包,如正常發行版、企業版等。由于密鑰對簽發的最小機關是宿主,一個宿主下不同APP使用的都是同一份配置,這會導緻兩個問題:
1)服務端無法區分流量來源;
2)宿主開發者濫用宿主資訊,造成APP身份不可信。
我們的解決方案是針對每一個接入的APP強制進行包簽名校驗。包簽名對于正式發版到應用商店的APP包是唯一的身份辨別,通過對包簽名的校驗,就確定了每一個握手的用戶端都是一個可信任的用戶端。
最後,業務方校驗。按照業務緯度,通過對業務方的校驗,沒有授信的業務方請求,就會在握手服務中被攔截;加上對業務方校驗,建立安全業務隔離機制,增強安全防固功能。業務方可以根據自己的需求,選擇統一網關(bdtls 握手服務)和業務方網關(bdtls SDK)其中的一種模式,進行握手服務。
此外需要說明的是,無論是手百,還是開源聯盟宿主,無論是内部業務還是外部業務,使用的都是同一個握手服務,協商生成有具備一定有效期的密鑰 master secret,并用業務相應的密鑰将其加密(即 skr),傳回給用戶端。
4.1.2 加解密服務
業務請求階段,根據握手的網關服務模式,提供了兩種接入方式:
- 統一網關接入:内務服務可以選擇挂載到小程式服務網關之下(服務網關已經內建 bdtls 插件),即可無侵入的擁有bdtls資料加解密功能;
- 業務方網關接入:bdtls提供了加解密的SDK,外部業務(比如:支付業務)通過內建SDK的方式實作對請求資料的解密和響應資料的解密。
在對業務資料進行加解密的過程中,主要的流程如下:
- skr 解密:業務方利用預先配置設定的密鑰将 skr 解密,獲得協商密鑰和過期時間等資訊;
- skr 過期校驗:如果發現該協商密鑰密鑰已經過期,則傳回 skr 過期的 Alert 資訊,此時用戶端會重新發起握手;
- 加解密:利用解密出的 secretKey 對業務資料進行解密和加密。
4.2 用戶端實作方案
圖1和圖2,代表兩個不同業務方的bdtls請求,不同點在于多通道的握手方式,圖1使用統一握手通道服務(小程式的握手服務),業務方不需要在自己的Server端部署握手服務,僅需要在用戶端設定統一握手模式,就可以用統一握手的密鑰對請求參數加密、傳回資料解密。圖2使用支付的握手通道服務(業務方自己的握手服務),業務方需要在自己的Server端部署握手服務(業務方網關),同時還要在用戶端設定目前業務方的access key。除了多通道握手方式支援外,用戶端還采用了以下政策,保證bdtls穩定、高效地運作。
4.2.1 政策1:多路握手合并
問題:
相同的業務方同時發起多個bdtls業務請求時,首次沒有密鑰,必須先通過握手這個關卡擷取到,這時在多線程下,會造成多次備援的握手情況,對于bdtls網關server的QPS會增大,這樣以來,我們的後端需要擴容更多的伺服器。是以,用戶端在密鑰有效期内,僅需要保證一次有效的握手就可以降低握手頻次,節省bdtls網關server的開銷。
方案:
- 為每個業務配置設定一個task,task管理自己的握手通路;
- 為每個握手通路獨立配置設定一個常駐線程,保證握手通路安全;
- 為每個握手通路增加“哨兵”機制,檢測握手的狀态;
- 握手中,所有的即将發起的業務請求任務都被加入到握手的block隊列中;
- 等握手結束,握手的block隊列将前面攔截的業務請求任務逐一分發。
4.2.2 政策2:密鑰資料緩存
問題:
每次握手後,得到密鑰資料(密鑰secretKey、密鑰辨別skr、密鑰有效時間、DH groupID),如果放在記憶體中進行管理,APP下次冷啟動,這些密鑰資料丢失,顯然密鑰的有效期時間作用域隻在APP的生命周期内有效,用戶端需重新發起一次握手請求,這樣以來會造成多餘無效請求。
方案:
- 将密鑰資料組合歸檔成一個可持久化的對象;
- 為每組密鑰資料按業務方配置設定一個緩存密鑰的key;
- 按照緩存密鑰的key,将歸檔的密鑰對象存儲到緩存區;
- 下次APP冷啟動,優選從緩存區擷取密鑰資料進行解檔為密鑰對象,業務方進行bdtls請求時,密鑰有效,就不需要發起握手請求,直接對業務的請求body體加密。
GEEK TALK
05
最佳實踐
bdtls作為百度智能小程式業務的基建能力,不僅在小程式的場景有應用,而且在百度内部其他業務也被逐漸推廣應用。
- 小程式所有開源宿主APP;
- 小程式核心業務:PMS(小程式包管理)、授權、swan.request端能力等;
- 百度内部業務:支付(聚合收銀台)、任務SDK(營運)、搜尋影視第三方資源轉碼等。
最近,通過國家網絡安全攻防演練(HVV)項目,健康寶小程式百度用戶端經受住外部嚴格的攻擊,成功守住百度的安全高地,本次安全防固部分使用了bdtls安全通信協定,進而證明了bdtls技術在安全上是可靠的。
GEEK TALK
06
小結
bdtls 是參考 TLS1.3 草案标準設計實作的,使用 DHE 來做密鑰協商,RSA 進行數字簽名,AES-GCM 作為對稱加密算法來對業務資料包進行認證加密,使用 HKDF 進行密鑰擴充,摘要算法為 SHA256。另外,結合具體的使用場景,bdtls 在 TLS1.3 的基礎上主要做了以下幾方面的工作:
- 輕量級。砍掉了用戶端認證相關的内容;直接内置簽名公鑰,避免證書交換環節,減少驗證時網絡交換次數。
- 安全性。選用的基礎密碼元件均是 TLS1.3 推薦、安全性高的密碼元件。
- 高可用性。伺服器的過載保護,確定伺服器能夠在容災模式下提供安全級别稍低的有損服務。
- 可擴充性。支援多宿主、多業務進行加解密服務。
在密鑰協商過程中,TLS1.3 提供了目前性能最優的密鑰協商套件算法-- ECDHE-ECDSA ,而bdtls提供的密鑰協商算法-- DHE-RSA 還需更新。同時,bdtls已經完全脫離小程式業務,可作為百度内部中台化的安全服務元件,提供給更多的業務使用。
END
參考資料:
[1] TLS 協定分析與現代加密通信協定設計
[2]The Transport Layer Security (TLS) Protocol Version 1.3
[3] TLS 1.2/1.3 加密原理
[4] 基于 TLS 1.3的微信安全通信協定 mmtls
作者:金媛寶、孤獨鍵盤手
來源:微信公衆号:百度Geek說
出處:https://mp.weixin.qq.com/s/VK0T_O__WaoZ9L-uQ1twhg