溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android開發中如何防范組件導出的風險

發布時間:2021-09-09 15:17:07 來源:億速云 閱讀:224 作者:柒染 欄目:開發技術

這篇文章將為大家詳細講解有關Android開發中如何防范組件導出的風險,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

前言

近年來,移動APP存在一個非常的重要的問題就是安全問題,造成的后果有可能是用戶的隱私泄露和財產損失等,對于一款成熟的APP或者是金融銀行類APP,這無疑是最致命的,所以對APP進行有效的防范也是很有必要。
近段時間,公司安排了某安全公司對我們的APP進行了全方面的安全測試,根據文檔檢測結果看,整體上看還是很安全的,其中有一項就是組件導出風險,接下來我們說說四大組件、組件導出必要性、風險以及如何防范。

一、四大組件

從事Android開發,我們都知道Android有四大組件, 分別是:

  • 活動(Activity),用于表現功能,是用戶操作的可視化界面,它為用戶提供了一個完成操作指令的窗口;

  • 服務(Service),后臺運行服務,不提供界面呈現;

  • 廣播接受者(Broadcast Receive),用于接收廣播;

  • 內容提供者(Content Provider),支持多個應用中存儲和讀取數據,相當于數據庫。

從這些組件簡單的介紹,我們知道它們的重要性,賦予了app更加豐富的功能,所以這四大組件的安全性對我們app和用戶來說就顯得更加地重要。

二、組件導出必要性

什么是組件導出呢?組件導出的意思就是組件可以被外部應用調用,我們可以在這四大組件聲明的清單文件設置組件是否導出,如下:

<activity
            android:exported="true"
            android:name=".other.ComponentActivity">
        </activity>

或者:

<activity
            android:name=".other.ComponentActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
            </intent-filter>
        </activity>

上面兩種方式都是Activity組件導出的方式,主要是exported的值",為true時表示導出,Activity中exported的默認值:

  • 沒有intent filter時,默認為false;

  • 有intent filter時,默認為true

Broadcast Receive和Service的默認值都跟Activity的一樣。
Content Provider中exported的默認值:

  •  當minSdkVersion或者targetSdkVersion小于16時,默認為true

  • 大于17時,默認為false

開發過程中,app會有一些特定需求會使用到三方SDK,如微信分享、支付、推送等功能,我們發現這里都有一個共同點,都會涉及到組件導出的問題,如微信的

WXEntryActivity:

<!-- 微信分享 -->
        <activity
            android:name="${applicationId}.wxapi.WXEntryActivity"
            android:exported="true"
            android:launchMode="singleTask"
            android:theme="@android:style/Theme.Translucent.NoTitleBar" />

這樣就會被安全機構檢測出來的,如果不設置WXEntryActivity為組件導出,微信分享等功能根本就調不起來,這是官方的寫法,我們認為這是必須要設置為組件導出,除非你把微信分享需求干掉,那業務不把你罵死;又或者是監聽網絡變化的廣播接收器(7.0版本以上只能代碼中動態注冊才能接收該廣播)、推送功能,集成過一些推送SDK都有印象,一些Service也會聲明android:exported="true"等等。

這些無可避免的組件導出,我們可以回復安全機構:微信分享、推送等功能必須設置組件導出,所以我們只有保證自己的四大組件的設置,確保其是安全的,這樣才能確保app處于比較安全的狀態,應付安全檢測,給你的領導一個交代。

三、組件導出風險

前面說明了組件的重要性、組件導出,那么組件導出的風險是什么呢?

  • Activity作為組成Apk的四個組件之一,是Android程序與用戶交互的界面,如果Activity打開了導出權限,可能被系統或者第三方的App直接調出并使用。Activity導出可能導致登錄界面被繞過、拒絕服務攻擊、程序界面被第三方惡意調用等風險。

  • Broadcast Receiver作為組成Apk的四個組件之一,對外部事件進行過濾接收,并根據消息內容執行響應,如果設置了導出權限,可能被系統或者第三方的App直接調出并使用。Broadcast Receiver導出可能導致敏感信息泄露、登錄界面被繞過等風險。S

  • ervice作為組成Apk的四個組件之一,一般作為后臺運行的服務進程,如果設置了導出權限,可能被系統或者第三方的App直接調出并使用。Service導出可能導致拒絕服務攻擊,程序功能被第三方惡意調用等風險。

  • Content Provider組成Apk的四個組件之一,是應用程序之間共享數據的容器,可以將應用程序的指定數據集提供給第三方的App,如果設置了導出權限,可能被系統或者第三方的App直接調出并使用。Content Provider導出可能導致程序內部的敏感信息泄露,數據庫SQL注入等風險。

接下來以Activity導出為示例,說明下其風險,其它組件類比就好。首先Activity要在清單文件AndroidManifest.xml注冊:

<activity android:name="com.littlejerk.sample.other.WebActivity"/>

Activity的啟動通常有兩種方法

  • 顯式啟動,需要指定啟動的Activity:

Intent intent = new Intent(getContext(),WebActivity.class);
        intent.putExtra("URL","https://blog.csdn.net");
        startActivity(intent);
  • 隱式啟動,Intent中不再包含需要啟動的具體的Activity類,而是通過Intent提供某些信息,系統去檢索符合啟動意圖的Activity,這里是通過意圖過濾器聲明Intent信息:動作(action)、數據(data)、分類(Category)、類型(Type),組件(Component)、和擴展信息(Extra)。

<!-- 通過隱式啟動的方式需要在AndroidManifest.xml文件聲明-->
        <activity android:name=".other.WebActivity">
            <intent-filter>
                <action android:name="com.littlejerk.sample.action.VIEW_URL" />
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

        //調用方式啟動WebActivity
        Intent intent = new Intent();
        intent.setAction("com.littlejerk.sample.action.VIEW_URL");
        intent.putExtra("URL","https://blog.csdn.net");
        startActivity(intent);

使用Action跳轉,如果有一個程序的AndroidManifest.xml中的某一個 Activity的IntentFilter段中 定義了包含了相同的Action,那么這個Intent就與這個目標Action匹配。如果這個IntentFilter段中沒有定義 Type、Category,那么這個 Activity就匹配了。但是如果手機中有兩個以上的程序匹配,那么就會彈出一個對話框來提示說明。

上面說過有IntentFilter,如果不指定android:exported,那么該值默認為true,外部的應用通過隱式意圖的方式也能將對應的組件啟動起來。這種情況我們就是我們說的組件導出,而導出則意味著很有可能存在安全問題,接下來看下WebActivity頁面:

Intent intent = getIntent();
        String url = intent.getStringExtra("URL");
        UILog.e(TAG, url.charAt(0));
        mTvContent.setText(url);

我們注意到WebActivity只是接收一個URL并且顯示出來(沒有加載這個URL),從這里我們可以看出URL并沒有做參數檢驗,應用可能會崩潰;因為該頁面又是可被三方應用調用的,這時候如果別人惡意傳遞一些不良的網頁信息,那你這個應用不攔截就直接加載了,則這個應用有可能就要下架了。

四、如何防范

我們以最常見的Activity為例說明了組件導出的風險,因為這個URL參數是我們處理的,我們可以防止應用空指針異常,這沒問題,但是上面也說如果加載了不良URL呢?其實組件導出的風險最根本原因是被別人調用了,那這樣有沒有辦法控制這個別人的范圍,只允許我們信賴的人去調用。
在這里不得不提Android的權限機制,Android的Permission檢查機制是用來控制一個應用擁有哪些執行權利。例如應用擁有拍照權限才能擁有拍照權利,那么我們是否可以通過權限來控制一個應用是否有啟動WebActivity的權利呢?
Android提供了自定義權限的能力,應用可以定義自己的權限,如在清單文件中自定義一個permission:

<permission
        android:label="允許打開WebActivity頁面權限"
        android:name="com.littlejerk.sample.permission.WEB"
        android:protectionLevel="signature" />

label:權限的描述

name:該權限的名稱,使用該權限時通過名稱來指定使用的權限

protectionLevel:該權限受保護的等級,這很重要,它有三個等級

  • signature:簽名級別權限,即權限的定義方和注冊方必須具有相同的簽名才有效

  • system:系統級別權限,即權限的定義方和注冊方必須為系統應用

  • signatureOrSystem :同簽名或系統應用,上述二者具備其一即可

權限定義完成,如何用它來保護暴露的組件呢,看下面代碼:

<!-- 通過隱式啟動的方式需要在AndroidManifest.xml文件聲明-->
        <activity
            android:permission="com.littlejerk.sample.permission.WEB"
            android:name=".other.WebActivity">
            <intent-filter>
                <action android:name="com.littlejerk.sample.action.VIEW_URL" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

在activity聲明時,activity標簽下有一個permission,通過permission就能指定保護該activity的權限名稱了,這樣,只有具有了該權限的activity才能啟動它(注意在定義方和使用方都要在清單文件中定義和聲明自定義的權限),在調用方的清單文件中聲明和使用該權限:

<!--調用方可不用聲明-->
    <permission
        android:label="允許打開WebActivity頁面權限"
        android:name="com.littlejerk.sample.permission.WEB"
        android:protectionLevel="signature" />
    <!--調用方必須申請此權限-->
    <uses-permission android:name="com.littlejerk.sample.permission.WEB"/>

有了權限的控制,activity組件導出的范圍就可控了,當我們公司應用間存在相互的組件調用時,就可以使用同簽名的權限來做限制,至于其它應用因為不是相同的簽名,所以它們無法調用我們暴露出去的組件,這很有效地規避了風險。

Activity是我們最常見的一個組件了,但是BroadcastReceiver用的地方也不少,一般安全評測都有提到這個組件的,我們有必要提一提它,其實各個組件的安全控制也可通過permission來控制的。
BroadcastReceiver的注冊有兩種方式

  • 靜態注冊,在Manifest中聲明注冊

  • 動態注冊,在代碼中依賴其他組件,通過registerReceiver注冊

BroadcastReceiver有廣播的發送方和接收方,所以當使用permission來校驗通信的時候一般都需要雙向校驗,即廣播的方送方和接收方都需要添加權限檢驗,保證發送方只將廣播發送給信賴的接收方,同樣的接收方也只接受來自信賴方的廣播。

廣播發送方

發送方需要在清單文件AndroidManifest.xml中聲明權限:

<permission
        android:label="聲明發送方權限"
        android:name="com.littlejerk.sample.permission.BROADCAST_SEND"
        android:protectionLevel="signature" />

然后使用sendBroadcast(Intent intent, String receiverPermission)方法發送廣播:

//發送廣播
        Intent intent = new Intent();
        intent.setAction("com.littlejerk.sample.broadcast.action.TEST");
        sendBroadcast(intent, "com.littlejerk.sample.permission.BROADCAST_SEND");

從receiverPermission字面意思就知道,接收廣播方必須要申請com.littlejerk.sample.permission.BROADCAST_SEND這個自定義權限,不然,無法接收到action通知,如接收方的清單文件AndroidManifest.xml:

<!-- 接收方需申請發送方權限-->
    <uses-permission android:name="com.littlejerk.sample.permission.BROADCAST_SEND"/>

如果接收方的廣播接收器不控制自己的權限,則同開發者應用只監聽com.littlejerk.sample.broadcast.action.TEST這個action就行了,但是為了雙重檢驗,我們也需要給接收方聲明自己的權限。

廣播接收方

我們定義一個廣播接收器TestReceiver:

public class TestReceiver extends BroadcastReceiver {
    private static final String TAG = "TestReceiver";

    //接收到廣播信息的回調
    @Override
    public void onReceive(Context context, Intent intent) {
        //對外來的參數應該做些合法的檢查
        String action = intent.getAction();
        if (TextUtils.isEmpty(action)) {
            return;
        }
        UILog.e(TAG, "action:" + action);
    }
}

接著在清單文件AndroidManifest.xml中聲明控制權限:

<permission
        android:label="聲明接收方權限"
        android:name="com.littlejerk.sample.permission.BROADCAST_RECEIVER"
        android:protectionLevel="signature" />

然后把這個控制權限給廣播接收器,接收器有兩種注冊方式
靜態注冊方式,在清單文件AndroidManifest.xml中:

<receiver
            android:name=".widget.receiver.TestReceiver"
            android:permission="com.littlejerk.sample.permission.BROADCAST_RECEIVER">
            <intent-filter>
                <action android:name="com.littlejerk.sample.broadcast.action.TEST"/>
            </intent-filter>
        </receiver>

然后是動態注冊方式,在你需要注冊的地方聲明:

Receiver receiver = new Receiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.littlejerk.sample.broadcast.action.TEST");
registerReceiver(receiver, intentFilter, "com.littlejerk.sample.permission.BROADCAST_RECEIVER", null);

這兩種注冊方式都可以,但是推薦使用動態注冊廣播的方式,因為Android O上為了App性能和功耗的考慮,對靜態注冊的廣播做了很大的限制,至于是什么限制,這里就不說了。
我們對接收器也做了權限限制,那么發送方也必須要申請這個權限才能發送action給它呀,所以發送方的清單文件AndroidManifest.xml中在原有的基礎上需要添加:

<!-- 發送方需申請接收方權限-->
    <uses-permission android:name="com.littlejerk.sample.permission.BROADCAST_RECEIVER"/>

至此,廣播的雙向檢驗就完成了,以上所有代碼都測試過了,沒有任何問題,很好地過濾了無關廣播,保護了組件的安全。

關于Android開發中如何防范組件導出的風險就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女