付亞男
(廣東郵電職業技術學院,廣東 廣州 510630)
近幾年全球信息化的發展,移動互聯網的生態系統日益龐大,市場上豐富的移動應用也越來越多,手機APP 為我們提供便捷服務的同時,Android 端主要的安全問題如信息泄露、扣費短信、惡意廣告、挖礦木馬、勒索軟件等也一直困擾著我們,若對應用中潛在的安全隱患不能夠及時發現和處理,一旦出現問題,無論是對公司或用戶,都將造成不可估量的傷害。因此,做好應用技術開發的安全策略、讓應用更安全更可靠的運行,是每個開發者義不容辭的責任。
本文從安全開發角度梳理了一個Android APP 需要關注的安全問題,主要從程序安全和數據安全兩個方面進行分析,如圖1所示。

圖1 APP 安全組成
在開發APP 過程中,許多開發者只關注如何實現功能,對Android 的安全機制理解不夠,導致發布在應用市場上的很多APP 存在安全漏洞。程序安全主要包括程序漏洞、代碼混淆、應用簽名、APK 加固這四個方面的安全,下面將對這四方面進行詳細分析。
1.1.1 程序漏洞
程序漏洞主要體現在以下幾個方面:
(1)AllowBackup 漏洞。Android 2.1 以上的系統可以為APP 提供應用程序數據的備份和恢復功能,當Android Manifest.xml 文件中的allowBackup 被設置為true 時,攻擊者可通過adb backup、adb restore 來對應用數據進行備份和恢復,從而獲取到用戶的敏感信息,如證件號、手機號、身份令牌等,造成用戶隱私數據的泄漏和資產損失,在正式發布應用之前,顯式設置為false,不能對應用數據備份。
(2)Java 動態調試風險。應用級配置文件build.gradle中的調試標記默認是true,即可以通過JDB 等調試工具進行調試,攻擊者可以訪問和篡改用戶敏感信息,甚至分析并修改相關業務邏輯的代碼,從而實現竊取用戶密碼,繞過驗證碼保護等違規操作,因此,應該在APP 正式發布之前,設置android:debuggable 屬性為false,關閉Java 動態調試功能,不允許被調試。
(3)程序包日志控制。一些開發者習慣在開發過程中打印調試日志,用于排查問題,卻沒能在調試完畢后及時刪除日志。調試函數日志中可能輸出重要的調試信息,諸如組件名、通信數據、跟蹤變量等,這些信息的打印會導致用戶信息、重要代碼事件流的泄漏,從而為攻擊者提供便利。對應用內Log 統一封裝控制基類,并判斷測試環境允許打印日志,正式環境關閉日志的輸出,或修改編譯器配置,對敏感代碼進行Inspections 提醒,告知開發者應做到及時刪除。
(4)WebView 漏洞攻防。WebView 漏洞包括四種情況,下面將做詳細介紹。
第一種JS 注入漏洞。惡意APP 可以注入JavaScript 代碼進入WebView 中的網頁,網頁未作驗證。惡意網頁可以執行JavaScript 反過來調用APP 中注冊過的方法,或者使用資源。這些惡意程序嵌入Web APP,然后竊取用戶信息,遠程調用APP 代碼。更有甚者,通過Java Reflection 調用Runtime 執行任意代碼。解決辦法主要:對于Android 4.2 及其以上版本,google 已經fix 該漏洞,只需要native interface上增加@addJavaInterface 標示即可;對于Android 4.2 以前的版本,則需要覆寫addJavaInterface()方法。
第二種WebView 釣魚漏洞。釣魚是最難使用技術手段解決的最常見攻擊,防釣魚技術層面可以做兩件事:一是檢查WebView 加載的目標鏈接是否存在安全風險;二是對WebView 關閉腳本環境。
第三種WebView 跨域漏洞。 主要是因為JS 的XmlHttpRequest 可以讀取系統存放cookie 的本地文件webviewCookiesChromium.db,等同于提供了對cookie 的讀訪問權限。針對Android 4.1 以及以上系統,本身不存在這個跨域漏洞,沒有針對性修改,其他版本系統可通過設置禁止從本地html 加載頁面來防止這個漏洞的出現。
第四種WebView 數據漏洞。安卓WebView 組件默認會引導用戶把明文形式的密碼保存到應用數據目錄的databases/webview.db 中,從而攻擊者可通過root 的方式訪問該文件,從而竊取用戶的用戶名和密碼。為了預防這個漏洞,可以通過設置savePassword()為false 來顯式關閉密碼存儲功能:WebView.getSettings().setSavePassword(false)。
(5)應用組件暴露。Android 系統共有四大組件:活動組件、服務組件、廣播組件、內容組件。如果組件暴露,攻擊者可以通過外部傳入Intent 來越權訪問,從而引起數據泄露、DOS 攻擊和應用連續崩潰等問題。所以在APP 應用中如果非必要,組件不要進行導出,在AndroidManifest.xml文件中,設置組件的exported 屬性為false;如果組件一定要提供給外部進行調用的話,可以對組件的權限進行控制。
(6)第三方sdk 組件。目前,大部分Android 應用都集成了很多的第三方SDK,有些第三方SDK 可能來自開源社區,安全性并沒有被驗證,如果存在安全問題,會產生用戶的隱私和財產安全被損耗等嚴重的后果。目前發生的第三方SDK 安全事件主要原因在以下兩方面:
1)第三方SDK 的開發者只關注實現功能,在安全方面的投入少,并且相關安全技術不高;
2)部分惡意開發者滲入了SDK 開發環節并通過吸引合法APP 的開發者來集成他們的SDK,從而躲避應用市場和安全廠商的檢測。因此,為保障第三方sdk 安全,可以采取下面措施:一是培養開發人員的安全意識。在開發過程的各個環節建立安全評估檢查點;開發環節嚴格遵守開發規范,防止類似調試后門等安全威脅的產生;應用發布前交給獨立的內部或外部測評組織進行安全性評估。二是防止APP被惡意篡改。規范APP 發布流程;防止應用簽名證書泄露;選擇正規渠道發布APP;應用升級更新時為防止運行被劫持的安裝包,一定要先校驗下載安裝包。
1.1.2 代碼混淆
APP 中的一些關鍵資源文件沒有進行加密保護,攻擊者可以從APP 中提取關鍵的資源文件,進行二次使用或從資源文件中獲取本地業務邏輯代碼,從而對APP 發起攻擊。例如對APP 進行關鍵邏輯篡改、植入惡意代碼、網絡協議分析等等。開啟代碼混淆minifyEnabled=true,有利于增加攻擊者反編譯獲取代碼的成本,且打包時移除無用資源,減少APK 體積;引入資源混淆如AndResGuard,將原本冗余的資源路徑變短,如“res/drawable/newerIcon”將變為“r/d/i”,可以再次優化減APK 體積,且混淆資源路徑后,使用APKTool 工具無法直接回編生成二次APK,也在一定程度上提升了APK 反破解難度。
1.1.3 應用簽名
應用簽名在保障設備安全方面發揮著重要作用,可用于進行權限檢查以及軟件更新。簽名一是保證消息來源的真實性,二是確保消息不會被第三方篡改,早期的V1 簽名會將APK 內文件進行逐一簽名并將簽名結果保存在ETA-INF 目錄下,V1 簽名的缺點一是簽名校驗速度較慢,在APK 安裝校驗過程中需要對所有文件進行摘要計算,在APK 資源較多、性能較差的機器上簽名校驗將花費較長時間,導致安裝速度慢,影響用戶體驗,且META-INF 目錄用來存放簽名,自然此目錄本身是不計入簽名校驗過程的,可以隨意在這個目錄中添加文件。升級到V2 版本簽名,V2 簽名將驗證歸檔中的所有字節,而不是單個ZIP 條目,因此在簽署后無法再運行重壓ZIP 包等,能夠及時發現對APK 的受保護部分進行的所有更改,從而有助于加快驗證速度并增強完整性保證。后續Android 9.0 引入了V3 版本簽名,在V2 插入的簽名塊中又插入了一個新塊,以秘鑰輪轉的方案,來做簽名的替換和升級,圖2為是推薦使用的APK 簽名流程圖。

圖2 APK 簽名流程圖
1.1.4 APK 加固
普通的APK 文件對攻擊者來說屬于裸奔狀態,被反編譯后能夠輕易得到明文資源和DEX 原代碼文件,因為常規的Android 程序代碼都將打包在DEX 和so 文件中,這些文件經過反編譯工具可以得到對應的源代碼閱讀。圖3為APK 加固圖,應用加固技術首先將原DEX 文件加密或者隱藏起來,然后放入一個新的殼DEX 到APK 中,最后程序啟動時先運行這個殼DEX,然后殼DEX 在運行時再加載原DEX,使得攻擊者不能直接通過APK 解壓輕易獲取到原代碼資料。

圖3 APK 加固圖
建議通過引入第三方加固平臺對混淆簽名后的APK 進行安全加固,從而進一步保證DEX、so、資源文件、數據文件等重要的APK 文件信息的安全性,加固后的APK 通過代碼插花、虛假控制流、字符串加密等手段提高了程序被破解的難度,能夠一定程度上防止靜態逆向、防篡改和二次打包,有效保護APP 的安全性。
數據安全包括網絡數據和本地數據兩個方面。早期的Http 協議是明文傳輸攻擊者可以輕易地通過Charles 或Fiddler 等抓包工具來攔截和篡改請求數據,雖然Android 9.0以后谷歌官方限制了默認不允許非加密的鏈接來改進對設備和數據安全的保護,但是Https 并不能直接阻擋攻擊者分析請求接口并發起惡意請求攻擊,數據之間的傳遞仍可被攻擊者輕易抓取到并進行篡改。
1.2.1 網絡數據
對于終端之間的通訊的數據安全,主要存在三個問題:
(1)傳輸內容可能被竊聽。
(2)傳輸內容可能被篡改。
(3)無法驗證雙方的身份。
為了保證數據的真實性和可靠性,一般通過加簽和加密兩種方式來提高數據交互的安全性。簽名校驗是對請求數據、請求頭參數進行一定規則的拼接和運算并進行結果簽名,生成唯一的結果sign 作為校驗字段,服務端接收到請求后進行唯一性驗簽校驗,至于簽名規則可雙方約定,這里的簽名規則相當于秘鑰的作用,可將簽名代碼Native 化,或增加花指令來進一步提高破解難度。數據加密是對提交到服務器和從服務器接收到的數據都進行加密后再傳輸。加密類型有多種手段,一般使用對稱加密和非對稱加密的混合方式進行,對稱加密的耗時較大,對大數據加密時存在一定的性能問題,Https 本身的加密處理也是類似,另外可以由后端控制公鑰的過期時間和刷新來保持秘鑰的動態性,進一步提高安全等級。
1.2.2 本地數據
本地數據包括三種情況:代碼中敏感URL、APP 中敏感數據、通用加密算法參數,如圖4所示。

圖4 本地數據情況組成
(1)代碼中敏感URL。直接將訪問的網址或訪問的IP地址硬編碼寫到代碼中,那么攻擊者通過反編譯APP 進行靜態分析,搜索URL 或IP 相關的信息,那么這些URL 或IP 信息就會成為攻擊者的一個利用目標。
(2)APP 中敏感數據。Android 主要有五種數據存儲方式:文件存儲、SharedPreferences 輕量級存儲、SQLite 數據庫存儲、ContentProvider 數據共享、網絡存儲。APP 運行時候會進行記錄或存儲一些敏感信息:個人隱私、登錄信息、本地驗證碼、聊天記錄,等等。SharedPreferences 存儲數據主要記錄存儲一些數據量較小的信息。存儲的信息直接可以用MT 管理工具或者直接用adb 復制傳輸到外部電腦主機上,再通過可視化工具進行打開查看文件,會造成配置信息或敏感的賬號信息泄露。攻擊方式有兩種方式:一是利用apktool 反編譯APP 應用,并進行查看二進制代碼數據就能直觀地看到敏感的操作調用敏感數據。二是通過代理模式進行抓包就可以直接抓到APP 運行中的操作的敏感數據。
(3)通用加密算法參數。代碼中往往會出現一些保護敏感信息的常量字符串,例如在代碼中硬編碼AES 加密的key、iv 等,或者用戶的VPN 密碼等等。因此,本地數據同樣需要進行加密存儲,如Sqlite 數據庫、SP 文件、SD 卡緩存、程序運行日志、本地資源文件等,加密過程可根據數據重要程度進行對稱加密或非對稱加密,且同樣建議將加密過程Native 化,相對于Java 代碼容易被反編譯,C++代碼編譯后生成的庫是一個二進制文件,能夠初步阻擋住一些逆向者。一些重要數據(用戶賬號密碼等),或者標記存儲本地的時候也應該進行加密,或者直接存儲hash 碼,而不能直接存儲明文。有些存儲本地的數據,比如令牌,就需要進行加密處理。登錄成功后的重要信息,如需要存儲本地,也需要加密。
本文通過探討Android APP 可能存在的安全問題,并從開發者角度提出相應的防護措施來加強Android APP應用的安全,從而對于保護Android應用程序的安全具有很高的價值和意義。