Android 常見安全漏洞修復理論與實踐

0xCAFEBOY發表於2019-06-16

前言

前段時間公司對應用在愛加密上進行了安全掃描,本文將基於愛加密的漏洞分析報告,針對部分內容,介紹理論修復實踐

最小化特權準則概念介紹

最小化特權準則,即指元件只能供自身應用呼叫,儘可能禁止其他應用訪問及呼叫。

違反最小化特權的危害

若元件違反最小化特權準則,則會帶來如下危害:

  1. 攻擊者惡意呼叫應用的 Activity, 修改程式的狀態或關鍵資料。舉個例子,如果您的應用的應用需要人臉認證才可以登入,一般需要儲存一個人臉認證狀態,如果攻擊者修改了人臉狀態,改為已認證通過,則可以直接進入應用主頁。

  2. 通過呼叫 Activity 內部的方法,可獲取私密資料,甚至造成拒絕服務和應用崩潰。例如,如果您的登入 Activity 違反了最小化特權準則,攻擊裝者可通過反射,來呼叫您的 Activity 有一個私有方法,用來獲取賬號和密碼。

解決方案

  1. 設定 Activity 元件 android:exported = false
  2. 必須 exported 的 Activity 元件必須僅限於授權使用者或者特定元件呼叫
  3. 謹慎使用 intent-filter 屬性,若必須使用,則需強制設定 android:exported = false

這裡涉及幾個概念,簡要介紹一下:

1. android:exported

適用於 Android 四大元件,其作用是控制其他應用程式是否可以與當前元件互動。其中 true 為可以與之互動。若設定為 false ,意味著對於 Service 元件,只有相同應用程式的元件或相同使用者 ID 的程式才能啟動或繫結該服務。值得注意的是,如果該元件在 AndroidManifest 中宣告瞭 intent-filter , 該元件的 exported 屬性將自動設定為 true。若沒有宣告,則預設為 false.

2. 使用者 ID (UID)

對於 Android 應用,每個應用程式都有一個 UID, 預設情況下,Android 系統會為每一個分配一個互不相同的 UID. 如果兩個應用的 UID 不同,則不能相互呼叫。若希望相互呼叫,可進行如下操作:

  1. 設定 android:sharedUserId 屬性,該屬性的作用是將一個或多個應用程式共享同一個 UID。具體程式碼如下所示:
  2. 兩個應用需使用相同的簽名檔案進行簽名
// 應用一
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.anna.hello"
    android:sharedUserId="anna.uid">

複製程式碼
// 應用二
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.anna.hello2"
    android:sharedUserId="anna.uid">

複製程式碼
3. 自定義安全許可權

該標籤用於在 AndroidManifest 中宣告一個安全許可權,可用於此應用程式的特定元件或功能的訪問。例如一個傳送廣播的業務,APK1 用於接收廣播,APK2 用於傳送廣播,APK1 此時僅想接收宣告瞭對應許可權的應用傳送的廣播。此時需要在 APK1 通過 定義安全許可權, 在 APK2 通過 申請 APK1 定義的安全許可權即可。 定義格式如下:

<permission 
    android:description="string resource"
    android:icon="drawable resource"
    android:label="string resource"
    android:name="string"
    android:permissionGroup="string"
    android:protectionLevel=["normal" | "dangerous" | 
                             "signature" | "signatureOrSystem"] /> 

複製程式碼
  • android:description 用於描述該許可權所針對的操作及使用者授予這個許可權的後果
  • android:label 用於描述該許可權
  • android:name 用於唯一標識許可權
  • android:permissionGroup 用於標識該許可權所屬許可權組的名稱
  • android:protectionLevel 用於標識該許可權的等級,可控制許可權的授予方式,normal 表示宣告後自動獲取,signature 表示定義許可權的 APK 和宣告許可權的 APK 必須使用同一簽名檔案,才可獲取許可權。

Activity 最小化特權漏洞修復

案例詳解 1

在本例中,IncomingDialog 為會議振鈴和外呼介面。由於 IncomingDialog 設定了 標籤 導致了android:exported = true, 因此,強制設定 exported 為 false 即可 修改前:

 		<activity
            android:name="cn.redcdn.incoming.IncomingDialog"
            android:process=":JMeetingService"
            android:screenOrientation="portrait"
            android:configChanges="orientation|screenSize|keyboardHidden"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
            <intent-filter>
                <action android:name="cn.redcdn.jmeetingsdk.start.incomingactivity" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
複製程式碼

修改後:

 <activity
            android:name="cn.redcdn.incoming.IncomingDialog"
            android:process=":JMeetingService"
            android:screenOrientation="portrait"
            android:exported="false"
            android:configChanges="orientation|screenSize|keyboardHidden"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
            <intent-filter>
                <action android:name="cn.redcdn.jmeetingsdk.start.incomingactivity" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
複製程式碼

這裡簡要介紹一下 android:enabled 屬性,該屬性適用於四大元件,控制該元件是否可以被系統初始化,預設為 true, 如果設定為 false, 對應控制元件無法初始化,例如無法啟動服務。值得注意的是, 標籤中也會可以宣告該屬性,而且該 enabled 與 元件宣告都為 true 的情況下元件才可被初始化。修改點同樣是將 exported 改為 false

資料越權備份風險

概念

應用資料備份

Android 2.1 系統可為 APP 提供資料的備份與恢復功能,可在 AndroidManifest 標籤下宣告 android:allowBackup, 屬性決定是否禁用該功能,其中 false 標識禁用。值得注意的是該屬性預設為 true

違反資料越權備份的危害

攻擊者可利用此漏洞攻擊任何可以開啟 USB 除錯的應用非 root 裝置。

  1. 通過 adb backup 命令,將制定應用的資料拷貝到外設。一旦該應用資料被備份後,所有的使用者在這個應用的SharedPreferencesDB都可被攻擊者讀取。
  2. 通過 adb restore 命令,可指定某個備份資料,恢復應用的資料

雖然可以對備份後的檔案(.ab)進行加密,但是仍有許多工具工具可對其解密,例如: android-backup-extractor, 下面將簡單介紹一下 adb backup 的用法

adb backup

adb backup [-system|-nosystem] -all [-apk|-noapk] [-shared|-noshared] -f <檔案名稱> [需要備份的應用包名]
複製程式碼

例如想備份包名為emergency.cicdi.com的資料,可以輸入如下程式碼:

adb backup -nosystem -noapk -f emergency.ab emergency.cicdi.com
複製程式碼

該命令會在當前目錄下生成名為 emergency.ab 的備份檔案。通過 android-backup-extractor ,可得到對應應用的SharedPreferencesDB檔案

解決方案

將 app module 下的 AndroidManifest.xml 中設定 android:allowBackup="false" 即可,但是這麼處理是不夠的,會遇到一個問題,由於我們的專案整合了多個依賴,比如掃碼二維碼的庫,和 IM Library, 依賴中 AndroidManifest 都預設設定 android:allowBackup="true" ,會導致編譯時不同 module 合併 AndroidManifest 檔案會產生衝突。需要解決衝突,即統一該屬性的取值。但是有些 library 是遠端依賴,本地專案並不可以編輯程式碼,而且一個一個修改未免效率較低,因此需要在 app module 下的 AndroidManifest.xml 中宣告

    <application
        ...
        tools:replace=" android:icon,theme,allowBackup" >
        ...
複製程式碼

這行程式碼標識 Manifest 合併規則,意味著當合並 library 中的 Manifest 檔案到主 App Manifest時,不考慮 library Manifest 中的 allowBackup 取值,以 app 中的 Manifest 為準進行合併。


堅持不易,您的點贊是我寫作的最大動力!

相關文章