值得細讀!如何系統有效地提升 Android 程式碼的安全性?

網易雲社群發表於2019-03-03


眾所周知,程式碼安全是Android開發工作中的一大核心要素。


11月3日,安卓巴士全球開發者論壇線下系列沙龍第七站在成都順利舉辦。作為中國領先的安卓開發者社群,安卓巴士近年來一直致力於在全國各大城市舉辦線下技術大會,為Android開發者提供最為全面深入的安全技術解讀。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


網易雲易盾移動安全專家尹彬彬指出,安全開發能有效降低開發者維護成本

網易雲易盾移動安全專家尹彬彬也受邀參加了此次會議,並做《如何提升Android程式碼的安全性》主題演講。針對Android開發者,他分享了在App開發週期的各個階段中常見的安全隱患,給出了提升Android程式碼安全性的建議,包括安全開發、程式碼加固、渠道監測、應用審計等Android程式碼安全技術剖析。


Android應用安全存在多重隱患


尹彬彬首先提到,Android和iOS兩大作業系統佔據了幾乎全部移動端的市場份額,但是相比後者,缺少足夠嚴格管控以及未能形成完善安全生態的Android系統,往往會存在很多安全隱患,給企業、開發者和使用者都帶來了不好的影響。


比如說:


  • 程式碼可逆向:客戶端App的邏輯能夠被輕易獲取和逆向,得到程式碼和程式中的敏感資料;

  • 功能洩漏:客戶端App中高許可權行為和功能被其他未授權的應用程式呼叫訪問;

  • 可除錯:客戶端App能夠被除錯,動態地提取、修改執行時的程式資料和邏輯;

  • 日誌資訊洩漏:客戶端App將開發時輔助除錯資訊列印洩露,包含敏感引數等資訊;

  • 可二次打包:客戶端App可能被修改程式碼,重新打包釋出在市場上供使用者下載;

  • 密碼學誤用:客戶端App程式碼中使用了不安全的密碼學實現,例如固定硬編碼的對稱加密,ECB模式的對稱加密,CBC模式中IV固定等;

  • 敏感資訊洩漏:客戶端App程式碼中洩漏敏感資料,如認證使用的共享金鑰、不應被暴露的後臺伺服器管理地址等;

  • 通訊資料明文傳輸:客戶端App與伺服器端互動的資料通過明文的通訊通道傳輸,或者加密傳輸,但資料依然可以被解密;

  • ......


隨著技術的不斷髮展升級,移動App安全防護髮展到現在的階段,也已經成功引入了“安全生態鏈”的概念,並出現了融入到整個App開發上線週期鏈中的全套安全服務,這個生態鏈包含了安全開發、應用審計、安全加固、渠道檢測等。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


  • 開發階段:開發者應遵循移動應用的安全開發規範,使用一些成熟的安全元件,如安全鍵盤SDK、防劫持SDK等,此外還需要定期對客戶端進行安全評估;

  • 測試階段:採用黑盒滲透攻擊和白盒程式碼審計的方式發現移動應用的安全缺陷及安全漏洞,降低安全風險;

  • 上線階段:上線前使用加固、混淆等技術加固應用,提高攻擊門檻和逆向的時間成本;

  • 運營階段:監控第三方應用市場,及時發現各種盜版、釣魚、山寨等惡意應用。


安全開發能有效降低開發者維護成本


安全開發是指在開發階段減少安全風險,從而將安全缺陷降低到最小程度,避免後期線上運營階段出現安全問題,但是成本較高。


安全開發生命週期(SDL)是側重於軟體開發的安全保證過程,旨在開發出安全的軟體應用。其核心理念就是將安全考慮整合在軟體開發的每一個階段:需求分析、設計、編碼、測試和維護。從需求、設計到釋出產品的每一個階段每都增加了相應的安全活動,以減少軟體中漏洞的數量並將安全缺陷降低到最小程度,儘可能地在產品版本回歸前清除漏洞。


尹彬彬表示,在這一階段,一方面可以開展SDL培訓,強化安全開發意識,制定安全編碼規範;另一方面是使用較成熟的安全元件。


具體的安全建議包括有:


  • 安全鍵盤:/dev/input/event可以讀取到按鍵和觸屏,實現安全鍵盤隨機佈局;

  • 金鑰安全:避免硬編碼金鑰在程式碼中,可以本地分段加密儲存,也考慮使用白盒金鑰;

  • 通訊安全:中間人攻擊,證照弱校驗等造成通訊協議被分析破解,需要對通訊資料加密校驗和證照有效性校驗;

  • 防介面劫持: Activity、對話方塊或者惡意懸浮窗劫持,導致使用者被釣魚或者誤接觸,需要防劫持;

  • 壞境監測:ROOT、模擬器、是否有惡意應用等壞境檢測,Xposed外掛、HOOK、偵錯程式檢測

  • 資料校驗:簽名校驗,最好實現在jni層,多點檢查、隱蔽呼叫位置,或者結合網路校驗,檢測APK中檔案是否被篡改,資料指紋;

  • 重點邏輯轉移到jni層實現:對重要邏輯從java層轉譯到jni層實現,結合程式碼混淆,提高分析難度;

  • 防日誌洩露:防止開發日誌洩露,通過開關控制,Java層通過proguard配置;

  • 防敏感資料洩露: 避免敏感資料明文儲存,考慮本地儲存加密(sharepreference、sqlite等);

  • 正確使用密碼學演算法:Hash演算法使用SHA-256代替MD5,AES不要使用ECB模式,初始化向量IV不要使用固定的常量,使用/dev/urandom或者/dev/random來初始化偽隨機數生成器,從而代替SecureRandom。


在開發階段、測試階段發現或者預防安全隱患成本較低,上線階段或者運營階段出現安全問題的成本較高,因此,開發者應明確安全開發的重要性。


應用審計


“只要是人在開發程式碼,就會存在安全漏洞”,尹彬彬如是說。近幾年來,安全漏洞的形式越來越多種多樣,拒絕服務、Webview明文儲存密碼等漏洞深切困擾著企業和開發者。因此,應用審計的重要性也越來越顯著。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


一般而言,應用審計的方式主要包括漏洞掃描和滲透測試。


1. 漏洞掃描


在漏洞掃描中,黑盒測試是比較常見的手段之一,也方便整合到現有的開發流程中。它能夠很方便地提供漏洞詳情、漏洞程式碼行數、風險等級、修復建議等。自動化移動應用安全測試框架Mobile Security Framework就是個很好的工具。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


2. 滲透測試


滲透測試可以有效檢測客戶端程式安全、敏感資訊保安、密碼軟鍵盤安全性、安全策略設定、手勢密碼安全性、通訊安全、配置檔案、拒絕服務、本地SQL隱碼攻擊等威脅型別。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


程式碼加固


程式碼加固主要包括應用加固(DEX檔案、SDK檔案、SO檔案)和原始碼混淆(Java、C/C++、JavaScript/HTML)兩種常見手段。


1. DEX加固


從Java到C++語言,越往底層走,系統的粒度就越來越細(檔案、方法、指令),殼邏輯與被加固的業務邏輯邊界也越來越模糊。所以要想獲得安全性和執行效率的平衡點,就可以採用DEX加固的方式。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


  • 記憶體載入:防止靜態分析;

  • 指令抽取:增大記憶體Dump的難度;

  • VMP保護:指令虛擬機器保護;

  • Java2C:將Java指令轉換為C執行。


2. SDK加固


Java位元組碼較容易被反編譯,拿到SDK基本等於直接獲取了原始碼。目前針對SDK的保護僅限於開發階段的Proguard混淆,沒有較高強度的安全保護措施。


但可以借用Dex加固的思想,對Java位元組碼做抽取處理:

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


3. SO加固


SO加密包括自定義節加密和自定義Linker,如下的例子所示:

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


  • 先確定ELF檔案,即構建被加殼SO檔案soinfo,再進行重定位修復:

  • 匯入函式地址,獲取並修復(將被加殼SO匯出函式對映到殼SO),執行init_proc和init_array;

  • 修復被加殼SO檔案,有效匯出函式、JNI_ONLOAD函式;

  • 執行被加殼SO Jni_Onload函式。


4. Java原始碼混淆


此方式下可以設定自己的字典,這也是最常用的安全防護手段之一。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


5. C/C++混淆


C/C++混淆可利用Obfuscator-LLVM工具高效實現,主要包括以下方法:


  • 控制流平坦化:在不改變原始碼功能的前提下,將C、C++等語言中的if、while、for、do等控制語句轉化為switch分支選擇語句。控制流平坦化有點像虛擬機器保護,case塊相當於vm的handle,case值相當於vm的opcode。

  • 指令替換:生成條件跳轉指令有兩種方法,一種稱為opaque predicate,另一種稱為bogus control flow。假設基本塊block0,opaque predicate後變為:if(恆等式){block0;}else{垃圾程式碼}或if(恆不等式){垃圾程式碼}else{block0;};bogus control flow後變為if(隨機條件){block0;}else{block1;},else的基本塊block1複製於block0。

  • 控制流偽造。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?



其他常見的C/C++混淆手段還有:


  • 多重分支;

  • 基本塊分割:把基本塊分成多個基本塊。有兩種方法:一種是根據概率對基本塊的當前指令進行分割;另一種是計算基本塊的總指令數,標記為a,隨機生成小於a的數,標記為b,基本塊b條指令後進行分割,a減掉b,進行多次迭代直至a等於1。

  • 字串加密;

  • 常量隱藏;

  • 常量展開;

  • 常量陣列隨機化:讓常量在陣列中的索引隨機化。假設常量陣列a[],索引值i,隨機生成索引陣列b[]、c[]、d[](可生成更多),迴圈用z[b[c[d[i]]]]=a[i]生成隨機後的常量陣列z[],然後用z[b[c[d[i]]]]替換a[i]。

  • 表示式變換:對邏輯操作not、and、or、xor,可以先把運算元抽取分成多個更小的數進行操作,最後用or連線起來,當然這四個操作可以用與非門或是或非門來完成。還有其它常見的運算可以把運算元看成大數然後進行大數運算,還有一些運算可以轉變為SIMD指令進行運算。至於浮點數,有很多浮點數的軟體實現可供參考。


6. H5混淆


H5混淆是指從JS的語法和邏輯上進行混淆。


這種是從抽象語法樹角度對JS的原始碼進行語法分析,將原始碼字串轉換為樹形結構,然後對相應的屬性(如字串、變數名、函式名等)進行混淆或加密。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?值得細讀!如何系統有效地提升 Android 程式碼的安全性?


渠道監測能夠隨時感知安全態勢


渠道監測也是Android安全開發中的一個重要課題,其工作內容主要是App是否被除錯、HOOK、脫殼等執行時資訊的上報,以便隨時感知安全態勢。


  • 爬蟲:監測主流渠道應用下載資料,包括第三方市場、論壇等;

  • 盜版識別:應用圖示、名稱、包名、資原始檔、程式碼指紋等,使用相似度演算法分析;

  • 資料分析:盜版渠道分佈、下載量、盜版溯源、篡改內容等資料分析。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


總結


“攻防沒有止境”,尹彬彬表示,通過安全編碼規範要求、上線前的安全檢測、程式碼加固、業務執行中基於網路通訊層的完整性校驗、標準化的SDL檢測等全方面的安全防護,能夠抵禦8-9成的攻擊,但是還是有可能會有新的安全問題出現。

值得細讀!如何系統有效地提升 Android 程式碼的安全性?


因此,他指出:“移動安全的方案需要更加貼合業務層面,與時俱進”。


網易雲易盾依託網易20年的技術積累及對數十條業務線的保障經驗,擁有海量特徵庫和成熟的安全機制,並結合超強雲端計算及人工智慧技術,形成對遊戲、金融、電商、娛樂等場景化解決方案,服務集團內外上千家客戶。“如果需要獲得更加可靠的移動安全保障,可以來和我們聊聊。”尹彬彬最後表示。


點選免費體驗網易雲易盾移動安全解決方案



相關文章:
【推薦】 “網易有錢”sketch使用分享


相關文章