概述
當Android應用程序需要訪問設備上的敏感資源時,應用程序開發人員會使用權限模型。雖然該模型使用起來非常簡單,但開發人員在使用權限時容易出錯,從而導致安全漏洞。本文中,首先將探討幾種不同類型的權限,然后解釋開發人員在實現權限模型時常犯的錯誤,以及如何避免這些錯誤。
權限聲明及其類型
權限有助于限制對某些Android組件,如活動、服務和內容提供商的訪問。開發人員可以在應用程序的AndroidManifest.xml文件中聲明各種權限類型。
權限還用于在運行時驗證應用程序是否有權訪問敏感信息或執行危險操作。例如,對于要訪問聯系人的應用程序,開發人員必須在其AndroidManifest.xml文件中包含uses-permission聲明:
<uses-permission android:name="android.permission.READ_CONTACTS" />
這是一個將protectionLevel設置為危險的內置權限。在實現此權限級別時,Android+系統會在安裝過程中詢問用戶是否愿意向此應用授予此類權限。如果用戶拒絕,則不會安裝該應用程序。
如果開發人員希望創建自己的權限,則必須在清單中聲明它,如下所示:
<permission android:name="com.mycoolcam.USE_COOL_CAMERA" android:protectionLevel="dangerous" />
<activity android:name=".CoolCamactivity" android:exported="true" android:permission="com.mycoolcam.USE_COOL_CAMERA"> <intent-filter> <action android:name="com.mycoolcam.LAUNCH_COOL_CAM" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
然后,如果第三方應用程序想要使用此示例的功能,則需要進行如下聲明:
<uses-permission android:name="com.mycoolcam.USE_COOL_CAMERA" />
并在安裝和使用時要求用戶授予權限。
除此之外,以下還列舉了一些其他權限級別,例如:
-
normal:此權限對用戶“不可見”。用戶不知道應用程序正在請求訪問此資源,因為在安裝過程中會自動授予權限。
-
dangerous:如前所述,此級別要求用戶確認應用程序是否可以訪問特定資源。
-
signature:使用此權限級別的應用程序必須使用與聲明它的應用程序相同的證書進行簽名。這可以防止攻擊者為此級別創建uses-permission聲明,因為 Android將不允許安裝該應用程序。
-
系統應用程序還使用其他幾個級別,如system、 installer、privileged等。從攻擊者的角度來看,這些應該被視為signature級別,即使用此保護級別的權限不能在 uses-permission中被聲明。
接下來,讓我們看看開發人員在使用權限時會犯的一些常見錯誤。
忘記protectionLevel保護等級
如果在權限聲明中沒有提到protectionLevel保護等級,則默認情況下它將被標記為normal,這將允許任何應用程序能夠使用它。三星內置應用程序的開發人員也犯了類似的錯誤,導致手機上的其他應用程序有可能讀取受害者的通話記錄、短信等。
<permission android:name="com.mycoolcam.USE_COOL_CAMERA" />
生態系統錯誤
假設開發人員有兩個應用程序的生態系統:My Cool Cam和My Cool Reader。閱讀器應用程序使用相機應用程序的功能。
相機應用程序的清單:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mycoolcam"> <permission android:name="com.mycoolcam.USE_COOL_CAMERA" android:protectionLevel="signature" /> <uses-permission android:name="com.mycoolcam.USE_COOL_CAMERA" /> <Application android:label="My Cool Cam"> <activity android:name=".CoolCamActivity" android:exported="true" android:permission="com.mycoolcam.USE_COOL_CAMERA"> <intent-filter> <action android:name="com.mycoolcam.LAUNCH_COOL_CAM" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <!-- ... --> </application>
閱讀器應用程序的清單:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mycoolreader"> <uses-permission android:name="com.mycoolcam.USE_COOL_CAMERA" /> <application android:label="My Cool Reader"> <provider android:name=".AllUserNotesContentProvider" android:authorities="com.mycoolreader.notes_provider" android:exported="true" android:permission="com.mycoolcam.USE_COOL_CAMERA" /> <!-- ... --> </application> </manifest>
乍一看,似乎一切都很好且安全,因為只有生態系統中的應用程序才能訪問存儲在 AllUserNotesContentProvider中的敏感信息。
但是,如果受害者的設備只安裝了閱讀器應用程序會發生什么?在這種情況下,Android系統將不知道com.mycoolcam.USE_COOL_CAMERA權限聲明的任何內容,因此默認情況下會將權限級別標記為normal。
為防止出現這種情況,請確保在每個應用程序中也分別聲明來自多個應用程序生態系統的每個權限。
權限名稱中的錯別字
開發人員在權限名稱中打錯字是非常常見的:
<permission android:name="com.mycoolcam.USE_COOL_CAMERA" android:protectionLevel="signature" />
<activity android:name=".CoolCamActivity" android:exported="true" android:permission="com.mycoolcam.USE_COOL_CAM"> <intent-filter> <action android:name="com.mycoolcam.LAUNCH_COOL_CAM" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
在以上示例中,com.mycoolcam.USE_COOL_CAMERA的權限的保護等級為signature,而com.mycoolcam.USE_COOL_CAM的將被設置為normal。這允許任意應用程序使用com.mycoolcam.USE_COOL_CAM進行使用權限聲明,從而授予對CoolCamActivity活動的訪問權。
組件聲明中的錯別字
<permission android:name="com.mycoolcam.USE_COOL_CAMERA" android:protectionLevel="signature" />
<activity android:name=".CoolCamActivity" android:exported="true" android:uses-permission="com.mycoolcam.USE_COOL_CAMERA"> <intent-filter> <action android:name="com.mycoolcam.LAUNCH_COOL_CAM" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
在以上示例中,它沒有使用android:permission屬性(設置組件的訪問級別),而是使用android:uses-permission。這將允許任何第三方應用程序訪問它,因為這意味著該組件沒有保護級別。
權限保護不足
某些應用程序并沒有完全保護他們使用的權限,這為第三方應用程序利用易受攻擊的應用程序并獲得權限留下了空間。
讓我們通過一個簡單的例子更好地理解這一點。
AndroidManifest.xml文件:
<uses-permission android:name="android.permission.READ_CONTACTS" />
<provider android:name=".ContactsProvider" android:authorities="com.exampleapp.contacts" android:exported="true" />
ContactsProvider.JAVA文件:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return getContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, selection, selectionArgs, sortOrder); }
在這種情況下,您可以清楚地看到訪問 URIContactsContract.CommonDataKinds.Phone(別名為//com.android.contacts/data/phones)需要android.permission.READ_CONTACTS權限。但是,訪問 content://com.exampleapp.contacts不需要任何權限。
為了防止這種情況,應用程序應該確保對其收到的任何權限進行保護。