談談我對Android安全機制的理解

LeoLiang發表於2015-12-31

本文從Android系統架構著手,分析Android的安全機制以SE Android,最後給出一些Android安全現狀和常見的安全解決方案。

1、Android系統架構

Android採用分層的系統架構,由下往上分別是linux核心層、硬體抽象層、系統執行時庫層、應用程式框架層和應用程式層。

Android以Linux作業系統核心為基礎,實現硬體裝置驅動、程式和記憶體管理、網路協議棧、電源管理等核心系統功能。除此以外,Android還增加了一些面向移動裝置的特有功能,如低記憶體管理LMK(Low Memory Killer)、匿名共享記憶體(Ashmem: Anonymous Shared Memory),以及程式間通訊Binder機制。這些功能的增強進一步提升了Android在記憶體管理、程式間通訊等方面的安全性。

Android之前的版本並不存在硬體抽象層。鑑於硬體廠商並不希望公開其裝置驅動的原始碼,Google對此將Linux核心驅動程式進行封裝,遮蔽掉底層的實現細節,向上提供統一的介面,這就是硬體抽象層。

HAL(Hardware Abstraction Layer)規定了一套應用層對硬體層的讀寫和配置的統一介面,本質上是將硬體的驅動分為使用者空間和核心空間,其中核心驅動程式執行在核心空間,HAL執行在使用者空間。上圖中的Stub,以so庫的形式存在,可以理解為proxy。上層通過呼叫標識獲得HAL的相關Stub,進而取得相應操作。

系統執行時庫由系統類庫和Android執行時構成。系統類庫基本上用C/C++編寫,基本功能說明如下:

系統類庫 功能說明
Surface Manager 執行多個應用程式時,管理子系統顯示,對2D和3D圖形提供支援
Media Framework 基於PacketVideoOpenCore多媒體庫,支援多種常用的音訊視訊格式錄製和回放。支援的編碼格式包括MPEG4、MP3、H.264、AAC、ARM
SQLite 本地小型關係型資料庫,以代替傳統的耗費資源JDBC API
OpenGL | ES 基於OpenGL ES 1.0 API標準實現的3D跨平臺圖形庫
FreeType 用於顯示點陣圖和向量字型
Webkit Web瀏覽器軟體引擎
SSL 安全套接層
SGL 底層2D圖形引擎
Libc(bionic libc) 繼承自BSD的C函式庫bionic libc,更適合基於嵌入式Linux的移動裝置

當然,還有Android NDK(Native Development Kit),使得應用程式可以不依賴Dalvik虛擬機器進行開發。Android執行時核心庫提供android.os, android.net, android.media等核心API,而Dalvik虛擬機器依賴Linux核心,實現程式隔離與執行緒排程管理、安全與異常管理、垃圾回收等功能,並被改進以適應低記憶體、低處理器速度的移動裝置環境。

再往上就是應用程式框架層了。一系列的Android應用程式所需的類庫,使得開發人員可以快速地進行程式開發,也可以通過繼承實現個性化的擴充套件。如Activity Manager負責主執行緒ActivityThread的建立、Activity生命週期的維護,併為視窗提供互動的介面。

應用層就是與使用者直接互動的應用程式,如SMS簡訊、圖片瀏覽器、地圖以及開發人員所開發的應用程式。

2、Android安全機制

Android將安全設計貫穿系統架構的各個層面,覆蓋系統核心、虛擬機器、應用程式框架層以及應用層各個環節,力求在開放的同時,也恰當保護使用者的資料、應用程式和裝置的安全。Android安全模型主要提供以下幾種安全機制:

  • 程式沙箱隔離機制
  • 應用程式簽名機制
  • 許可權宣告機制
  • 訪問控制機制
  • 程式通訊機制
  • 記憶體管理機制

程式沙箱隔離機制,使得Android應用程式在安裝時被賦予獨特的使用者標識(UID),並永久保持。應用程式及其執行的Dalvik虛擬機器執行在獨立的Linux程式空間,與其它應用程式完全隔離。

在特殊情況下,程式間還可以存在相互信任關係。如源自同一開發者或同一開發機構的應用程式,通過Android提供的共享UID(Shared UserId)機制,使得具備信任關係的應用程式可以執行在同一程式空間。

應用程式簽名機制,規定APK檔案必須被開發者進行數字簽名,以便標識應用程式作者和在應用程式之間的信任關係。在安裝應用程式APK時,系統安裝程式首先檢查APK是否被簽名,有簽名才能安裝。當應用程式升級時,需要檢查新版應用的數字簽名與已安裝的應用程式的簽名是否相同,否則,會被當做一個新的應用程式。Android開發者有可能把安裝包命名為相同的名字,通過不同的簽名可以把他們區分開來,也保證簽名不同的包不被替換,同時防止惡意軟體替換安裝的應用。

許可權宣告機制,要想獲得在物件上進行操作,就需要把許可權和此物件的操作進行繫結。不同級別要求應用程式行使許可權的認證方式也不一樣,Normal級申請就可以使用,Dangerous級需要安裝時由使用者確認,Signature和Signatureorsystem級則必須是系統使用者才可用。

訪問控制機制,確保系統檔案和使用者資料不受非法訪問。

程式通訊機制,基於共享記憶體的Binder實現,提供輕量級的遠端程式呼叫(RPC)。通過介面描述語言(AIDL)定義介面與交換資料的型別,確保程式間通訊的資料不會溢位越界。

Linux程式視角

應用程式視角

記憶體管理機制,基於Linux的低記憶體管理機制,設計實現了獨特的LMK,將程式重要性分級、分組,當記憶體不足時,自動清理級別程式所佔用的記憶體空間。同時,引入的Ashmem記憶體機制,使得Android具備清理不再使用共享記憶體區域的能力。

正是因為Android採用多層架構,在保護資訊保安的同時,也保證開放平臺的靈活性。

3、SE Android

Android是一個基於Linux核心的系統,像傳統的Linux系統一樣,Android也有使用者的概念。只不過這些使用者不需要登入,也可以使用Android系統。Android系統將每一個安裝在系統的APK都對映為一個不同的Linux使用者。也就是每一個APK都有一個對應的UID和GID,這些UID和GID在APK安裝的時候由系統安裝服務PackageManagerService分配。Android沙箱隔離機制就是建立在Linux的UID和GID基礎上。

這種基於Linux UID/GID的安全機制存在什麼樣的問題呢?

Linux將檔案的許可權劃分為讀、寫和執行三種,分別用字母r、w和x表示。每一個檔案有三組讀、寫和執行許可權,分別針對檔案的所有者、檔案所有者所屬的組以及除了所有者以及在所有者所屬組的使用者之外所有其它使用者。這樣,如果一個使用者想要將一個自己建立的檔案交給另外一個使用者訪問,那麼只需要相應地設定一下這個檔案的其它使用者許可權位就可以了。所以,在Linux系統中,檔案的許可權控制在所有者的手中。因此,這種許可權控制方式就稱為自主式的,正式的英文名稱為Discretionary Access Control,簡稱為DAC。

在理想情況下,DAC機制是沒有問題的。然而,一個使用者可能會不小心將自己建立的檔案的許可權位錯誤地修改為允許其它使用者訪問。如果這個使用者是一個特權使用者,並且它錯誤操作的檔案是一個敏感的檔案,那麼就會產生嚴重的安全問題。這種誤操作的產生方式有三種:

  • 使用者執行了錯誤的命令
  • 負責執行使用者命令的程式有Bug
  • 負責執行使用者命令的程式受到攻擊

後來,Linux核心採用了必要的訪問控制機制:SE Linux(Security-Enhanced Linux),它採用了一種強制存取控制MAC(Mandatory Access Control)策略的實現方式,目的在於通過限制系統中的任何程式以及使用者對資源的訪問,保護核心安全。而SE Android(Security-Enhanced Android)是Android與SE Linux的結合,由美國NSA在2012年推出的Android作業系統安全強化套件,以支援在Android平臺上使用SE Linux。

目前SE Android系統中的策略機制主要有三種:

  • 安裝時MAC(install-time MAC)
  • 許可權取消(permission revocation)
  • 許可權標籤傳播(tag propagation)

安裝時MAC通過查詢MAC策略配置來檢查應用程式的許可權。許可權取消可以為已安裝的應用取消許可權,該機制在應用程式執行的許可權檢查時通過查詢許可權取消列表來取消應用的某些許可權。許可權標籤傳播是一種汙點跟蹤方式的應用,Android系統的許可權作為抽象的標籤對映到MAC策略配置檔案中。

SE Android安全機制所要保護的物件是系統中的資源,這些資源分佈在各個子系統中。實際上,系統中需要保護的資源非常多,除了檔案之外,還有程式、socket和IPC等。SE Android是一個複雜的安全模型,本文就不進一步分析了。想了解更多,請參考:SEAndroid安全機制框架分析

4、Android應用安全解決方案

Android應用會遇到各種各樣的安全性問題,如何從巨集觀上了解各種安全隱患,積極採取適當的防禦措施便變得尤為重要。那麼,Android應用面臨哪些安全問題呢?

  • 病毒
  • 關鍵資訊洩露
  • APP重打包
  • 程式被劫持
  • 資料在傳輸過程遭劫持
  • Webview漏洞

病毒不用多說了,都是一些惡意軟體。關鍵資訊洩露,可能有些開發者並不十分留意。雖然Java程式碼可以做混淆,但是Android的幾大元件的建立方式是依賴注入的方式,因此不能被混淆。而且目前常用的一些反編譯工具比如apktool等能夠毫不費勁地還原Java裡的明文資訊,native裡的庫資訊也可以通過objdump或IDA獲取。因此一旦Java或native程式碼裡存在明文敏感資訊,基本上就是毫無安全而言的。重打包即通過反編譯後重新加入惡意的程式碼邏輯,重新打包一個APK檔案。程式被劫持一般通過程式注入或者除錯程式的方式來hook程式,改變程式執行的邏輯和順序,從而獲取程式執行的記憶體資訊。hook需要獲取root許可權或者跟被hook程式相同的許可權。如果手機沒被root,被劫持的可能性還是較小。資料在傳輸過程遭劫持,一般來說是由於資料明文傳輸或沒使用HTTPS。Webview漏洞一般由於JS注入。

現實中,出現的問題可能比上面提及的還要多。總的來說,應該從以下幾個方面來應對Android開發的常見安全問題:

  • 應用許可權控制。通過控制應用程式的許可權防止惡意應用對系統造成破壞,採取的措施包括合理使用系統內建許可權和應用程式自定義許可權。
  • 應用程式簽名。採用數字簽名為應用程式簽名。
  • 應用加固。應用加固包括病毒掃描、防注入、防除錯、防篡改四個模組,目前行業內已經出現了很多的應用加固解決方案,如360應用加固、騰訊雲應用加固、百度應用加固等等。
  • 靜態程式碼分析。通過靜態程式碼分析工具lint監測安全隱患,對程式碼進行優化。
  • 防火牆。必要時為Android裝置安裝防火牆,以防止遠端網路攻擊。
  • 資料儲存加密。採用加密的方式保護應用程式敏感資料,如利用SQLCipher加密SQLite資料庫。
  • 應用程式元件開發的安全要點。Activity, Service, Content Provider, Broadcast Receiver等元件在程式碼層面應採取的安全措施。它們每一個都可以通過隱式的Intent方式開啟,所以這些元件只要不是對外公開的必須在AndroidManifest裡面註明exported為false,禁止其它程式訪問我們的元件。對於要和外部互動的元件,應當新增訪問許可權的控制,還需要要對傳遞的資料進行安全的校驗。

相關文章