溫馨提示×

溫馨提示×

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

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

Android開發(fā)中如何防范組件導(dǎo)出的風(fēng)險

發(fā)布時間:2021-09-09 15:17:07 來源:億速云 閱讀:171 作者:柒染 欄目:開發(fā)技術(shù)

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

前言

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

一、四大組件

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

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

  • 服務(wù)(Service),后臺運行服務(wù),不提供界面呈現(xiàn);

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

  • 內(nèi)容提供者(Content Provider),支持多個應(yīng)用中存儲和讀取數(shù)據(jù),相當(dāng)于數(shù)據(jù)庫。

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

二、組件導(dǎo)出必要性

什么是組件導(dǎo)出呢?組件導(dǎo)出的意思就是組件可以被外部應(yīng)用調(diào)用,我們可以在這四大組件聲明的清單文件設(shè)置組件是否導(dǎo)出,如下:

<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組件導(dǎo)出的方式,主要是exported的值",為true時表示導(dǎo)出,Activity中exported的默認值:

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

  • 有intent filter時,默認為true

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

  •  當(dāng)minSdkVersion或者targetSdkVersion小于16時,默認為true

  • 大于17時,默認為false

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

WXEntryActivity:

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

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

這些無可避免的組件導(dǎo)出,我們可以回復(fù)安全機構(gòu):微信分享、推送等功能必須設(shè)置組件導(dǎo)出,所以我們只有保證自己的四大組件的設(shè)置,確保其是安全的,這樣才能確保app處于比較安全的狀態(tài),應(yīng)付安全檢測,給你的領(lǐng)導(dǎo)一個交代。

三、組件導(dǎo)出風(fēng)險

前面說明了組件的重要性、組件導(dǎo)出,那么組件導(dǎo)出的風(fēng)險是什么呢?

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

  • Broadcast Receiver作為組成Apk的四個組件之一,對外部事件進行過濾接收,并根據(jù)消息內(nèi)容執(zhí)行響應(yīng),如果設(shè)置了導(dǎo)出權(quán)限,可能被系統(tǒng)或者第三方的App直接調(diào)出并使用。Broadcast Receiver導(dǎo)出可能導(dǎo)致敏感信息泄露、登錄界面被繞過等風(fēng)險。S

  • ervice作為組成Apk的四個組件之一,一般作為后臺運行的服務(wù)進程,如果設(shè)置了導(dǎo)出權(quán)限,可能被系統(tǒng)或者第三方的App直接調(diào)出并使用。Service導(dǎo)出可能導(dǎo)致拒絕服務(wù)攻擊,程序功能被第三方惡意調(diào)用等風(fēng)險。

  • Content Provider組成Apk的四個組件之一,是應(yīng)用程序之間共享數(shù)據(jù)的容器,可以將應(yīng)用程序的指定數(shù)據(jù)集提供給第三方的App,如果設(shè)置了導(dǎo)出權(quán)限,可能被系統(tǒng)或者第三方的App直接調(diào)出并使用。Content Provider導(dǎo)出可能導(dǎo)致程序內(nèi)部的敏感信息泄露,數(shù)據(jù)庫SQL注入等風(fēng)險。

接下來以Activity導(dǎo)出為示例,說明下其風(fēng)險,其它組件類比就好。首先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提供某些信息,系統(tǒng)去檢索符合啟動意圖的Activity,這里是通過意圖過濾器聲明Intent信息:動作(action)、數(shù)據(jù)(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>

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

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

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

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

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

四、如何防范

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

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

label:權(quán)限的描述

name:該權(quán)限的名稱,使用該權(quán)限時通過名稱來指定使用的權(quán)限

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

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

  • system:系統(tǒng)級別權(quán)限,即權(quán)限的定義方和注冊方必須為系統(tǒng)應(yīng)用

  • signatureOrSystem :同簽名或系統(tǒng)應(yīng)用,上述二者具備其一即可

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

<!-- 通過隱式啟動的方式需要在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標(biāo)簽下有一個permission,通過permission就能指定保護該activity的權(quán)限名稱了,這樣,只有具有了該權(quán)限的activity才能啟動它(注意在定義方和使用方都要在清單文件中定義和聲明自定義的權(quán)限),在調(diào)用方的清單文件中聲明和使用該權(quán)限:

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

有了權(quán)限的控制,activity組件導(dǎo)出的范圍就可控了,當(dāng)我們公司應(yīng)用間存在相互的組件調(diào)用時,就可以使用同簽名的權(quán)限來做限制,至于其它應(yīng)用因為不是相同的簽名,所以它們無法調(diào)用我們暴露出去的組件,這很有效地規(guī)避了風(fēng)險。

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

  • 靜態(tài)注冊,在Manifest中聲明注冊

  • 動態(tài)注冊,在代碼中依賴其他組件,通過registerReceiver注冊

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

廣播發(fā)送方

發(fā)送方需要在清單文件AndroidManifest.xml中聲明權(quán)限:

<permission
        android:label="聲明發(fā)送方權(quán)限"
        android:name="com.littlejerk.sample.permission.BROADCAST_SEND"
        android:protectionLevel="signature" />

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

//發(fā)送廣播
        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這個自定義權(quán)限,不然,無法接收到action通知,如接收方的清單文件AndroidManifest.xml:

<!-- 接收方需申請發(fā)送方權(quán)限-->
    <uses-permission android:name="com.littlejerk.sample.permission.BROADCAST_SEND"/>

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

廣播接收方

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

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

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

接著在清單文件AndroidManifest.xml中聲明控制權(quán)限:

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

然后把這個控制權(quán)限給廣播接收器,接收器有兩種注冊方式
靜態(tài)注冊方式,在清單文件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>

然后是動態(tài)注冊方式,在你需要注冊的地方聲明:

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);

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

<!-- 發(fā)送方需申請接收方權(quán)限-->
    <uses-permission android:name="com.littlejerk.sample.permission.BROADCAST_RECEIVER"/>

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

關(guān)于Android開發(fā)中如何防范組件導(dǎo)出的風(fēng)險就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI