Android的安全性和權限(Security and Permission)(二)

聲明和強制實施權限

要強制執行自己的權限,首先必須使用一個或多個<permission>標簽,在AndroidManifest.xml文件中來聲明它們。

例如,應用程序想要控制誰能夠啟動它的一個Activity,就能夠用下面的方法來為這個操作聲明一個權限:

<manifestxmlns:android="http://schemas.android.com/apk/res/android"
    package="com.me.app.myapp">
    <permissionandroid:name="com.me.app.myapp.permission.DEADLY_ACTIVITY"
        android:label="@string/permlab_deadlyActivity"
        android:description="@string/permdesc_deadlyActivity"
        android:permissionGroup="android.permission-group.COST_MONEY"
        android:protectionLevel="dangerous"/>
    …
</manifest>

<protectionLevel>屬性是必須的,它告訴系統怎樣把應用程序需要的權限通知給用戶,或者是允許誰擁有這個權限。

<permissionGroup>屬性是可選的,並且隻用於幫助系統把相關權限顯示給用戶。通常用標準的系統組來設置這個屬性,當然也可以使用自己定義的組(但這很少見)。我們推薦使用既存的分組,這樣會簡化給用戶的顯示的權限UI。

要註意的時,權限所支持的label和description屬性。它們是能夠顯示給用戶的字符串資源,android:label屬性用於權限列表的顯示,android:description屬性用於單一權限的詳細介紹。label屬性值應該是簡短的,用幾個關鍵的單詞來描述被權限保護的功能。description屬性應該是權限的詳細描述,慣例是使用兩句話,第一句話來描述權限的功能,第二句話用來警告用戶,如果應用程序獲得瞭這個權限會帶來的不利影響。

下面是一個申請CALL_PHONE權限的label和description屬性設置的例子:

<stringname="permlab_callPhone">directly call phone numbers</string>
    <stringname="permdesc_callPhone">Allows the application to call
        phone numbers without your intervention. Malicious applications may
        cause unexpected calls on your phone bill. Note that this does not
        allow the application to call emergency numbers.</string>

用系統的Settings應用程序和shell命令:adb shell pm list permissions,能夠查看系統中當前定義的權限。Settings應用的使用方法是:Settings->Applications,選擇一個應用程序,向下滾動,可以看到這個應用程序所使用的權限。對於開發者,帶有“-s”選項的adb命令可以用與用戶查看格式相類似的格式來顯示權限:

$ adb shell pm list permissions -s
AllPermissions:

Network communication: view Wi-Fi state, create Bluetooth connections, full
Internet access, view network state

Your location: access extra location provider commands, fine (GPS) location,
mock location sources for testing, coarse (network-based) location

Services that cost you money: send SMS messages, directly call phone numbers

在AndroidManifest.xml中的強制權限

限制訪問系統或應用程序整個組件的高級別權限,能夠通過應用程序的AndroidManifest.xml文件來設定。所有這些都要求在被期望的組件上包含android:permission屬性,以及用於控制訪問的命名權限。

Activity的權限(應用於<activity>標簽)限制瞭誰能夠啟動被關聯的Activity。在Context.startActivity()方法和Activity.startActivityForResult()方法執行期間要檢查這個權限,如果調用者沒有要求的權限,那麼就會從調用中拋出一個SecurityException異常。

Service的權限(應用於<service>標簽)限制瞭誰能夠啟動或綁定被關聯的服務。在Context.startService()方法、Context.stopService()方法和Context.bindService()方法執行期間會檢查這個權限,如果調用者沒有要求的權限,那麼就會從調用中拋出一個SecurityException異常。

BroadcastReceiver的權限(應用於<receiver>標簽)限制瞭誰能夠發送廣播通知給關聯的接收器。在Context.sendBroadcast()方法返回後會檢查這個權限,也就是在系統試圖把提交的廣播通知發送給設定的接收器的時候。在因沒有權限而失敗的時候,它不會向調用者拋出一個異常,它隻是不發送Intent對象。同樣,給Context.registerReceiver()方法提供的權限,是用來控制誰能夠向程序中註冊的接收器發送廣播。另一種方式是,在調用Context.sendBroadcast()方法時,提供一個權限,來限制那個BroadcastReceiver對象能夠接收廣播通知。

ContentProvider的權限(應用於<provider>標簽)限制瞭誰能夠訪問ContentProvider對象中的數據。(內容提供有一套額外的叫做URI權限的重要且易用的安全權限,稍後會介紹。)跟其他組件不同,它有兩個獨立的權限屬性:android:readPermission用於限制誰能夠從提供器中讀取數據;android:writePermission用於限制誰能夠向提供器中寫入數據。要註意的是,如果提供器受到讀寫權限的保護,隻擁有寫權限並不意味著能夠從提供器中讀取數據。在首次獲取提供器和執行提供器相關的操作時,會進行權限的檢查(如果沒有權限,就會拋出一個SecurityException異常)。使用ContentResolver.query()方法查詢數據時,要求具有讀權限,使用ContentResolver.insert()方法、ContentResolver.update()方法、ContentResolver.delete()方法編輯數據時,要求具有寫權限。在所有的場景中,如果沒有要求的權限,這個調用就會導致一個SecurityException異常被拋出。

發送廣播時的強制權限

除瞭強制誰能夠把Intent對象發送給一個BroadcastReceiver對象的權限之外,在發送一個廣播通知時,還可以指定需求權限。通過調用帶有權限字符串的Context.sendBroadcast()方法,可以要求接收器必須要擁有這個權限,才能夠接受這個廣播通知。

要註意的是,接收器和廣播器都能夠要求權限,發生這種情況時,雙方的權限都必須檢查通過後,才可以把Intent對象發送給匹配的目標。

其他強制性權限

在調用Service過程中,可以設置更細粒度的權限。這種設置是通過調用Context.checkCallingPermission()方法來完成的。調用時給這個方法傳入所期望的權限字符串,它會返回一個整數,它指明瞭所期望的權限是否被當前調用的進程所接受。要註意的是,這種方法隻能在執行來自另一個進程調用的時候使用。通常通過IDL接口來發佈服務,或者是用其他的方法提供給另一個進程。

有很多有用的檢查權限的方法。如果有另一個進程的PID,那麼就可以使用Context.checkPermission(String, int, int)方法,針對這個PID來檢查權限。如果有另一個應用程序的包名,就可以直接使用包管理器的PackageManager.checkPermission(String, String)方法來找出這個包是否已經被授予瞭指定的權限。

URI權限

到目前為止我們所介紹的標準的權限系統不能滿足內容提供器的使用需要。內容提供器可能要保護它自己的讀寫權限,但是為瞭某些操作,它的客戶端也需要把指定的URI交給另一個應用程序來處理。一個典型的示例是Mail應用程序中的附件。郵件的訪問應該是受到權限的保護,因為這個用戶敏感的數據。但是,如果要把一個圖片附件的URI提供給一個Image瀏覽器,那麼這個Image瀏覽器就會因沒有權限而不能打開這個圖片附件。

這個問題的解決方案是給每個URI都分配一個權限,當啟動一個Activity或給一個Activity返回結果時,調用者能夠設置Intent.FLAG_GRANT_READ_URI_PERMISSION和(或)Intent.FLAG_GRANT_WRITE_URI_PERMISSION權限。這樣就給接受Intent對象的Activity授予瞭訪問Intent對象中指定的數據URI的權限,而不管它是否有權訪問與這個Intent對象對應的內容提供器中的數據權限。

這種機制允許使用一種共同的能力樣式模型,這種模型利用用戶交互(打開一個附件、選擇一個通訊錄等)來驅動設定更細粒度的權限。這種機制可以有效的減少應用程序所需要的權限,隻需要那些與它們直接相關行為權限。

這種把權限細化到URI的做法,需要持有這些URI的內容提供器的配合。強烈推薦內容提供器實現這種機制,並且通過android:grantUriPermissions屬性或<grant-uri-permissiongs>標簽來聲明它們所提供的權限。

更多的信息能夠在Context.grantUriPermission()、Context.revokeUriPermission()和Context.checkUriPermission()方法中找到。

 

摘自 FireOfStar的專欄

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。