??如果你喜歡我寫的文章,可以把我的公眾號設為星標 ??,這樣每次有更新就可以及時推送給你啦,
前段時間我們公司的一個大佬從一些渠道得知了一些小道訊息,某國民級 APP 因為 Apple App Store 審核人員檢測出 React Native 熱更新的內容,被拒審了三個月,我們的熱更新平臺和出事的 APP 原理相似,所以也存在著拒審危險,那么我們就要想一些辦法,隱藏熱更新 bundle,不被審核人員發現,
其實這個問題蠻復雜的,因為它不單純是一個技術問題,還涉及到各種復雜的商業利益,在諸多的限制條件下,你很難去找到一個最優解,而且這個問題也比較敏感,我也只能大致講一下我的思路,具體的代碼實作本文也不會提供,
??鄭重宣告:若有人按本文思路隱藏熱更新資料導致應用拒審或下架,本人概不負責
一、商業利益
Apple 公司對 iPhone 生態有著非常嚴格的管控:App 上架必須走 App Store,元件要參與簽名,帶 JIT 功能的虛擬機不能用......
對于熱更新技術,Apple 在 2017 年封殺過一次 JSPatch 這個熱更新框架,導致很多的 APP 被拒審,根據 Apple 官方給出的理由,主要有三點:
熱更新代碼沒有做好加密和校驗,有可能被第三方破解劫持 JSPatch 權限過高,可能會呼叫私有 API,改變原有的 APP 功能 對于 Apple 官方來說,JSPatch 自由度太大,會繞過 App Store 這個 iOS 上的唯一流量分發平臺更新應用,影響商業利益
俗話說得好,斷人財路如殺人父母,這種涉及商業利益的事情無論放在誰都頭上都忍不了,而且很多應用又不是微信,有龐大的用戶基數可以和 Apple 官方談判(微信小程式生態就是談出來的,但是小程式支付權限就沒談妥),所以說這個問題還是很復雜的,
其實對于 Apple 官方來說,對與動態化熱更新的態度向來是不贊成也不反對,和 JSPatch 比起來,React Native 和游戲熱更新這兩種應用場景還是被允許的,主要還是體現在三點:
網游這種重運營的場景還是需要熱更新維持活動熱度的,每周都有新活動,讓用戶主動去 App Store 下載更新包很不合理,App 活動運營同理 React Native/Lua 等熱更新技術是在一個容器里進行動態化的,不像 JSPatch 有那么大的修改權限 蘋果官方在商業利益上和游戲廠商/互聯網巨頭達到一些微妙的平衡
說實話蘋果審核一直很迷,拒審有時候和打太極一樣,給出的規范各路解讀都不一樣,不過為了保險起見,我們還是要研究一下相關的平臺規范,
二、解讀規范
2015 年蘋果發過一篇協議——《Apple Developer Program License Agreement》,文中第 3.3.2 節有一段關于熱更新的內容:
??Except as set forth in the next paragraph, an Application may not download or install executable code. Interpreted code may only be used in an Application if all scripts, code and interpreters are packaged in the Application and not downloaded. The only exceptions to the foregoing are scripts and code downloaded and run by Apple's built-in WebKit framework or JavascriptCore, provided that such scripts and code do not change the primary purpose of the Application by providing features or functionality that are inconsistent with the intended and advertised purpose of the Application as submitted to the App Store.
這一段話大概就是說除了 Webkit 和 JavascriptCore 可以動態執行下發的腳本和檔案,其它所有腳本/代碼/解釋器都必須打包在 APP 內部,這句話其實就給 React Native 留了一個口子:React Native 就是用 JavascriptCore 執行 JS 腳本檔案的,那么動態下發也是合理的,
??Interpreted code may be downloaded to an Application but only so long as such code: (a) does not change the primary purpose of the Application by providing features or functionality that are inconsistent with the intended and advertised purpose of the Application as submitted to the App Store, (b) does not create a store or storefront for other code or applications, and (c) does not bypass signing, sandbox, or other security features of the OS.
這一段話大概就是說,我允許你熱更新,但是必須遵循我這三條規定:
不能大的修改 APP 功能,導致應用實際功能和 APP Store 的宣傳不符(這個地方就很打太極,評判標準全靠審核人員心情) 不能動態創建應用商店(應該是不能繞過 IAP 支付的意思,要不然怎么收蘋果稅) 不能繞過簽名/沙箱/OS 的安全功能(這個可以理解,維護系統和生態安全)
這樣解讀下來,貌似只要按照規范當個良民就可以解決問題了,但是說實話,動態化規范更多的是君子協議,如果雙方都講武德,那大家其樂融融都挺好;萬一哪個人跳出來要壞規矩,說實話大家都很難堪,在未來,熱更新技術肯定還是要以微妙的平衡狀態存在下去,
三、技術實作
每次設計一些工程方案時,我個人的習慣都是先從理論上找答案,就拿隱藏熱更新 bundle 這個例子來說,我們主要是想在資訊傳輸這里找到突破口,實際上香農老爺子 1949 年就提出了一個「香農一韋弗通信模型」,這個模型里把通信分為五個部分:資訊源、發射器、信道、接收器、資訊接受者 和 噪音,

那么結合這個通信模型,我們隱藏/加密通訊資訊的答案就呼之欲出了:
對信源加密:在資訊的收發終端發送訊息時加密,接受訊息時解密 對信道加密:資訊在信道傳輸時,經過信道時進行加密
那么我們下面就對這兩個大方向進行擴展和探討,
1.對訊息本身加密/混淆
1.1 隱寫術——當代特洛伊木馬
隱寫術是一個非常非常古老的技術,這個技術的關鍵就是把想要傳遞的資料隱藏/偽裝一下,不讓第三方看出來真實想要傳遞的資料,
隱寫術的例子非常多,比如說特洛伊木馬,你從外面看是個木馬,但運到城里,士兵就跑出來了;我們看的一些影視劇里,也有類似原理的橋段:主角收到一份無字信紙,在蠟燭上一烤,文字就顯現出來,如今的數字時代肯定不會用無字信紙秘密傳遞訊息,我們肯定有些更加賽博的方法,比如說圖種技術——把訊息隱寫到圖片檔案里,
如果大家玩過一段時間貼吧,對圖種技術肯定不會陌生,有些大神會發個貼,把種子檔案隱藏在圖片里,大家把圖片下載下來,把 .jpg 的后綴改為 .zip or .rar,然后解壓檔案就能得到隱藏的種子檔案,然后在貼吧留下「樓主好人」的美譽,
那么圖種技術的原理是啥?其實很簡單,它只是單純的把一個 jpg 檔案和一個 rar 檔案合并在一起,但是圖片查看器會忽略附加的 rar 檔案資料,這樣在感官上這是一張圖片,但是從二進制的角度看這個圖片檔案里隱藏了一些資料,
下面我們看看圖種檔案的原理,
首先我用圖片編輯器生成一個 2x2 4 個像素大小的圖片——RGBY.jpg,顏色我參考 Google logo 配了一下:

然后我們用二進制查看工具(我這里用的是 Hex Fiend 軟體)查看這個圖片的編碼,因為圖片只有 4 個像素,所以二進制資料也會比較小,注意觀察這個檔案的二進制資料,它是 FF D8 開頭,FF D9 結尾的,
圖片查看器加載一張圖片檔案時就會做檢測,如果是 FF D8 開頭,就會認為這是一張 jpg 圖片,然后就會進入 jpg 圖片解碼的分支,加載二進制資料遇到 FF D9 后,就會認為這個圖片已經加載完畢,后面的資料就不會再管了,

基于圖片預覽器不會加載 FF D9 之后資料的這個特性,我們可以把一些要隱藏的資料附加到 jpg 檔案之后,
這里為了測驗方便,我新建了一個內容為 hello word 的 text.txt 檔案,然后用 cat 命令把 RGBY.jpg 和 text.txt 合并一下,生成 RGBY_text.jpg 檔案:
cat RGBY.jpg text.txt > RGBY_text.jpg
這時候用圖片瀏覽器查看檔案,可以看出檔案還是正常預覽的:

但是用二進制查看工具查看這張圖片,就會發現他在末尾多了 11 個位元組,正是 text.txt 里的內容—— hello word :

這樣我們就達到了隱寫的目的,
大家不要覺得這個方案 low,實際上阿里的一些密鑰就是通過類似的原理寫到一張圖片里的(當然不會像以上案例那么簡單),我們在傳輸熱更新 bundle 檔案時,可以把 bundle 檔案隱寫在一張圖片里,這樣審核人員在做流量監控的時候,抓包看到的是一張圖片,如果不檢查圖片的二進制編碼,是不會發現里面隱藏了資料的,
針對這種方案,服務端和客戶端的改動都比較小,服務端只需要每次下發 bundle 時前合并一個圖片檔案,客戶端讀取隱寫圖片后去掉多余的圖片資料就可以了,
當然隱寫識訓有很多種,比如說基于 LSB 的圖片隱寫技術,把資料寫在 jpg png mp4 的擴充資料欄位里,因為原理大同小異,這里就不多介紹了,感興趣的同學可以自行搜索學習,
1.2 對稱加密
對稱加密也是一個歷史悠久的加密技術,在資訊技術的加持了下也飛速發展,我舉個最簡單的對稱加密演算法——異或演算法加密,
異或運算我想每一個程式員都不陌生,我們先約定 0 為 false, 1 為 true,那么 XOR 運算的真值表如下:
| A | B | A ⊕ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
從真值表可以很容易推出下面的運演算法則:
運用上面的運算規則,我們假設 是密鑰,對內容 加密,那么得到的密文就是 ;想對密文解密,只要讓密文和密鑰 再進行一次異或運算就可以了:
我們可以用代碼舉例子驗算一下:
// 加密:
// 原文 密鑰 秘文
01010111 ^ 11110011 = 10100100
// 解密:
// 秘文 密鑰 原文
10100100 ^ 11110011 = 01010111
眾所周知,位運算都是非常快的,如果要簡單地對 bundle 做個混淆,直接用異或加密,基本上不會影響性能,
雖然異或運算很簡單,但是密碼學有個第一準則:永遠不要自己實作加密演算法,我們可以用已經非常成熟的對稱加密演算法(例如 AES 和 DES)對 bundle 進行加密:性能高,安全性好,最重要的是開源社區都有現成的庫,直接調包就可以了,
所以如果用對稱加密的方案,只要服務端和客戶端商量好一個密鑰,然后服務端用密鑰加密 bundle,客戶端用同一個密鑰解密,就能在一定程度上繞過 App Store 的例外流量檢測,
1.3 非對稱加密
非對稱加密是屬于近代密碼學的內容了,非常的新,但是也非常的可靠,具體原理太復雜了,一句兩句根本說不清楚,我就不做介紹了,
在加密熱更新 bundle 這個場景下,其實和對稱加密的效果差不多,只不過換成私鑰加密公鑰解密了,
1.4 總結
一般來說,對 bundle 加密不會單純使用一種技術,比如說我們會用混合加密的方式對 bundle 本身加密,用訊息認證碼(例如 HMAC)防篡改,加入時間戳亂數防重放,最后再把加密后的資料進行隱寫......這里面的組合實在是太多了,個人認為參考一些經典的加密組合進行業務實踐即可,
2.對信道加密
信道加密在本文的場景下也比較直觀,就是使用 HTTPS 協議,目的就是防止審核人員通過抓包的方式捕獲到我們的熱更新流量,當然 HTTPS 也有很多的有意思的知識點,下面我就簡單介紹一下,
2.1 使用 HTTPS
2021 年了,我想互聯網上基本沒有裸露的 HTTP 明文流量了吧......前幾年可能還會有企業考慮 HTTPS 加密帶來的服務器成本,但在各大平臺(iOS/Android/Chrome)的要求下,除了個別無人維護的網站,基本都全站上 HTTPS 了,畢竟現在資料的價值遠遠高于服務端的電費,上了 HTTPS 后,起碼被中間人攻擊被劫持的概率會降低不少,
上 HTTPS 就高枕無憂了嗎?那肯定不是,我去年寫過一篇 Charles 抓包的文章,里面花了大量的篇幅去介紹 HTTPS 抓包,既然一個 APP 開發者可以借助市場上的工具進行抓包,那么審核人員更可以了,在抓包工具下,大部分 HTTPS 資料都可以被捕獲和劫持,下面我們就說說 HTTPS 協議中一些比較高階的內容,
2.2 HTTPS 證書固定
HTTPS 證書固定,又叫 HTTPS 證書鎖定,英文名為 Certificate Pinning,指的是我們在 APP 內置僅接受指定域名的證書,而不接受作業系統或瀏覽器內置的CA根證書對應的任何證書,
通過這種授權方式,我們可以保障 APP 與服務端通信的唯一性和安全性,如果開啟了抓包軟體,不主動匯入固定的證書,就無法有效的抓包(具體原理可看我的博文:Charles 抓包原理),我想審核人員還沒那個精力去砸殼你的 APP 獲取你的證書,所以可以通過這種方式隱藏你的熱更新 bundle,
當然,證書固定也是有一定代價的,CA 簽發證書都存在有效期問題,所以缺點是在證書續期后需要將證書重新內置到 APP 中,
2.3 HTTPS 雙向認證
我們平常使用 HTTPS 時,一般只做了單向認證,即客戶端認證服務端的真實性,其實 HTTPS 支持雙向認證的,即支持服務端認證客戶端的真實性(具體流程可見下圖 * 部分),

一般來說開啟 HTTPS 雙向認證的 APP 都是那種安全性要求極高的 APP,比如說金融類 APP 和匿名社交類 APP,而且想要實作雙向認證,就必須要在客戶端內置一份公鑰證書和私鑰,但 APP 又有砸殼風險,所以還得想辦法把這兩個東西加密和隱寫(都成俄羅斯套娃了),
綜合來看,實作 HTTPS 雙向認證的成本還是很高的,但是一旦實作,安全系數還是非常高的,不僅僅是繞過審核人員的流量檢測,綜合來看整個 APP 的網路安全都得到了極大的防護,
四、總結
對于熱更新這件事,根據 Apple 的應用規范,基于 JavaScriptCore 的熱更新是完全可行的,但前提是你必須守規矩,不能脫離 Apple 的掌控范圍;但是 App Store 的審核規則又極其不透明,雖然我們是良民,但是一定程度上還是要隱藏一下熱更新 bundle,規避不必要的麻煩;隱藏熱更新 bundle 我們可以從信源加密和信道加密兩個角度去思考,綜合來看就是靈活利用密碼學知識,對網路資料進行加密,防止被檢測出例外流量,隱藏 bundle 的同時,也保護了用戶的資料安全,降低被攻擊的可能性,
五、參考閱讀
?? 為什么你的 Charles 會抓包失敗?
??如果你喜歡我的文章,希望點贊?? 收藏 ?? 在看 ?? 三連支持一下!!!謝謝你,這對我真的很重要!
歡迎大家關注我的微信公眾號:鹵蛋實驗室,目前專注前端技術,對圖形學也有一些微小研究,
也可以加我的微信 egg_labs,歡迎大家來撩,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/254340.html
標籤:其他
上一篇:作業
