Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的安全與訪問權限控制

Android中的安全與訪問權限控制

編輯:關於Android編程

Android是一個多進程系統,在這個系統中,應用程序(或者系統的部分)會在自己的進程中運行。系統和應用之間的安全性是通過Linux的facilities(工具,功能)在進程級別來強制實現的,比如會給應用程序分配user ID和Group ID。更細化的安全特性是通過"Permission"機制對特定的進程的特定的操作進行限制,而"per-URI permissions"可以對獲取特定數據的access專門權限進行限制。

安全架構

Android安全架構中一個中心思想就是:應用程序在默認的情況下不可以執行任何對其他應用程序,系統或者用戶帶來負面影響的操作。這包括讀或寫用戶的私有數據(如聯系人數據或email數據),讀或寫另一個應用程序的文件,網絡連接,保持設備處於非睡眠狀態。

一個應用程序的進程就是一個安全的沙盒。它不能干擾其它應用程序,除非顯式地聲明了"permissions",以便它能夠獲取基本沙盒所不具備的額外的能力。它請求的這些權限"permissions"可以被各種各樣的操作處理,如自動允許該權限或者通過用戶提示或者證書來禁止該權限。應用程序需要的那些"permissions"是靜態的在程序中聲明,所以他們會在程序安裝時就被知曉,並不會再改變。

應用程序簽名

所有的Android應用程序(.apk文件)必須用證書進行簽名認證,而這個證書的私鑰是由開發者保有的。該證書可以用以識別應用程序的作者。該證書也不需要CA簽名認證(注:CA就是一個第三方的證書認證機構,如verisign等)。Android應用程序允許而且一般也都是使用self-signed證書(即自簽名證書)。證書是用於在應用程序之間建立信任關系,而不是用於控制程序是否可以安裝。簽名影響安全性的最重要的方式是通過決定誰可以進入基於簽名的permisssions,以及誰可以share 用戶IDs。

用戶IDs和文件存取

每一個Android應用程序(.apk文件)都會在安裝時就分配一個獨有的Linux用戶ID,這就為它建立了一個沙盒,使其不能與其他應用程序進行接觸(也不會讓其它應用程序接觸它)。這個用戶ID會在安裝時分配給它,並在該設備上一直保持同一個數值。

由於安全性限制措施是發生進程級,所以兩個package中的代碼不會運行在同一個進程當中,他們要作為不同的Linux用戶出現。我們可以通過使用AndroidManifest.xml文件中的manifest標簽中的sharedUserId屬性,來使不同的package共用同一個用戶ID。通過這種方式,這兩個package就會被認為是同一個應用程序,擁有同一個用戶ID(實際不一定),並且擁有同樣的文件存取權限。注意:為了保持安全,只有當兩個應用程序被同一個簽名簽署的時候(並且請求了同一個sharedUserId)才會被分配同樣的用戶ID.

所有存儲在應用程序中的數據都會賦予一個屬性-該應用程序的用戶ID,這使得其他package無法訪問這些數據。當通過這些方法getSharedPreferences(String, int), openFileOutput(String, int), or openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory)來創建一個新文件時,你可以通過使用MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE標志位來設置是否允許其他package來訪問讀寫這個文件。當設置這些標志位時,該文件仍然屬於該應用程序,但是它的global read and/or write權限已經被設置,使得它對於其他任何應用程序都是可見的。

Using Permissions使用權限

一個基本的Android程序通常是沒有任何permissions與之關聯的,這就是說它不能做任何擾亂用戶或破壞數據的勾當。那麼為了使用設備被保護的features,我們就必須在AndroidManifest.xml添加一個或多個 標簽,用以聲明你的應用程序需要的permissions.
下面是個例子。

<manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.app.myapp"> <uses-permissionandroid:name="android.permission.RECEIVE_SMS"/> ... manifest>

應用程序安裝的時候,應用程序請求的permissions是通過package installer來批准獲取的。package installer是通過檢查該應用程序的簽名和/或用戶的交換結果來確定是否給予該程序request的權限。在用戶使用過程中不會去檢查權限,也就是說要麼在安裝的時候就批准該權限,使其按照設計可以使用該權限;要麼就不批准,這樣用戶也就根本無法使用該feature,也不會有任何提示告知用戶嘗試失敗。

很多時候, 一個permission failure會導致一個SecurityException被拋回該應用程序. 但是Android並不保證這種情況會處處發生。例如,當數據被deliver到每一個receiver的時候,sendBroadcast(Intent) 方法會去檢查permissions,在這個方法調用返回之後,你也不會收到任何exception。幾乎絕大多數情況,一個permission failure都會打印到log當中。

Android系統定義的權限可以在Manifest.permission中找到。任何一個程序都可以定義並強制執行自己獨有的permissions,因此Manifest.permission中定義的permissions並不是一個完整的列表(即有肯能有自定義的permissions)。

一個特定的permission可能會在程序操作的很多地方都被強制實施:

當系統有來電的時候,用以阻止程序執行其它功能;

啟動一個activity的時候,會控制誰可以啟動你的Acitivity;

在發送和接收廣播的時候,去控制誰可以接收你的廣播或誰可以發送廣播給你;

當進入並操作一個content provider的時候;

當綁定或開始一個service的時候。

聲明和使用Permissions

為了實現你自己的permissions,你必須首先在AndroidManifest.xml文件中聲明該permissions.通常我們通過使用一到多個 tag來進行聲明。
下面例子說明了一個應用程序它想控制誰才可以啟動它的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>

這裡屬性是需要聲明的(通常系統自有的permission都會有它對應的protection level,而我們自己定義的permission一般都需要定義protecdtion level,若不去定義,則默認為normal)。通過聲明該屬性,我們就可以告知系統如何去通告用戶以及通告哪些內容,或者告知系統誰才可以擁有該permission。具體請參看鏈接的文檔。

這我多說兩句啊,這個protectionLevel分四個等級,分別是Normal, Dangerous, Signature, SignatureOrSystem, 越往後安全等級越高。

這個屬性是可選項, 只是用於幫助系統顯示permissions給用戶(實際是告知系統該permission是屬於哪個permission group的)。你通常會選擇使用標准的system group來設定該屬性,或者用你自己定義的group(更為罕見)。通常使用一個已經存在的group會更合適,因為這樣UI顯示的時候會更簡單。

需要注意的是label和description都是需要為permission提供的。這些都是字符串資源,當用戶去看permission列表(android:label)或者某個permission的詳細信息(android:description)時,這些字符串資源就可以顯示給用戶。label應當盡量簡短,之需要告知用戶該permission是在保護什麼功能就行。而description可以用於具體描述獲取該permission的程序可以做哪些事情,實際上讓用戶可以知道如果他們同意程序獲取該權限的話,該程序可以做什麼。我們通常用兩句話來描述permission,第一句描述該permission,第二句警告用戶如果批准該權限會可能有什麼不好的事情發生。下面是一個描述CALL_PHONE permission的label和description的例子:

<stringname="permlab_callPhone">directly call phone numbersstring> <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>

你可以通過shell指令 adb shell pm list permissions 來查看目前系統已有的permissions. 特別的,"-s"選項會以一種用戶會看到的格式一樣的格式來顯示這些permissions.

在AndroidManifest.xml中強制使用Permissions

通過AP的AndroidManifest.xml文件可以設置該AP中各個組件的訪問權限,包括Activity,

Service,BroadcastReceiver,ContentProvider。這些組件中都包含android:permission屬性,設置這個屬性就可以控制訪問該組件的權限。

Activity permissions權限限制了誰才可以啟動相應的activity。Permission會在Context.startActivity()和Activity.startActivityForResult()的時候進行檢查,如果caller沒有所需的權限,則會拋出一個SecurityException。

Service permissions用於限制誰才可以start或bind該service。在Context.startService() , Context.stopService() 和 Context.bindService() 調用的時候會進行權限檢查。如果caller沒有所需的權限,則會拋出一個SecurityException。

BroadcastReceiver permissions用於限制誰才可以向該receiver發送廣播。權限檢查會在Context.sendBroadcast() 返回時進行,由系統去發送已經提交的廣播給相應的Receiver。最終,一個permission failure不會再返回給Caller一個exception;它只是不會去deliver該Intent而已。同樣地,Context.registerReceiver() 也可以有自己permission用於限制誰才可以向一個在程序中注冊的receiver發送廣播。另一種方式是,一個permission也可以提供給Context.sendBroadcast() 用以限制哪一個BroadcastReceiver才可以接收該廣播。

ContentProvider permission用於限制誰才可以訪問ContentProvider提供的數據。(Content providers有一套另外的安全機制叫做URI permissions,這些在稍後討論)不同於其它的Components,這裡有兩種不同的permission屬性可以設置: android:readPermission 用於限制誰可以讀取provider中的數據,而 android:writePermission 用於限制誰才可以向provider中寫入數據。需要注意的是如果provider既被read permission保護,也被write permission保護的話,如果這時只有write permission並不意味著你就可以讀取provider中的數據了。當你第一次獲取provider的時候就要進行權限檢查(如果你沒有任何permission,則會拋出SecurityException)。當使用 ContentResolver.query() 時需要讀權限,而當使用 ContentResolver.insert() , ContentResolver.update() , ContentResolver.delete() 時需要寫權限。在所有這些情況下,沒有所需的permission將會導致SecurityException被拋出。

在Sending Broadcasts時強制使用Permissions

除了之前說過的Permission(用於限制誰才可以發送廣播給相應的broadcastReceiver),你還可以在發送廣播的時候指定一個permission。在調用Context.sendBroadcast() 的時候使用一個permission string,你就可以要求receiver的宿主程序必須有相應的permission。值得注意的是Receiver和broadcaster都可以要求permission。當這種情況發生時,這兩種permission檢查都需要通過後才會將相應的intent發送給相關的目的地。

其它強制使用Permissions的方式

在調用service的過程中可以設置任意的fine-grained permissions(這裡我理解的是更為細化的權限)。這是通過Context.checkCallingPermission(String) 方法來完成的。呼叫的時候使用一個想得到的permission string,並且當該權限獲批的時候可以返回給呼叫方一個Integer(沒有獲批也會返回一個Integer)。需要注意的是這種情況只能發生在來自另一個進程的呼叫,通常是一個service發布的IDL接口或者是其他方式提供給其他的進程。

Android提供了很多其他的方式用於檢查permissions。如果你有另一個進程的pid,你就可以通過context method Context.checkPermission(String, int, int) 去針對那個pid去檢查permission。如果你有另一個應用程序的package name,你可以直接用PackageManager method PackageManager.checkPermission(String, String) 來確定該package是否已經擁有了相應的權限。

URI Permissions

到目前為止我們討論的標准的permission系統對於content provider來說是不夠的。一個content provider可能想保護它的讀寫權限,而同時與它對應的直屬客戶端也需要將特定的URI傳遞給其它應用程序,以便其它應用程序對該URI進行操作。一個典型的例子就是郵件程序處理帶有附件的郵件。進入郵件需要使用permission來保護,因為這些是敏感的用戶數據。然而,如果有一個指向圖片附件的URI需要傳遞給圖片浏覽器,那個圖片浏覽器是不會有訪問附件的權利的,因為他不可能擁有所有的郵件的訪問權限。

針對這個問題的解決方案就是per-URI permission: 當啟動一個activity或者給一個activity返回結果的時候,呼叫方可以設置Intent.FLAG_GRANT_READ_URI_PERMISSION 和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION . 這會使接收該intent的activity獲取到進入該Intent指定的URI的權限,而不論它是否有權限進入該intent對應的content provider。

這種機制允許一個通常的capability-style模型,這種模型是以用戶交互(如打開一個附件, 從列表中選擇一個聯系人)為驅動,特別獲取更細粒化的權限。這是一種減少不必要權限的重要方式,這種方式主要針對的就是那些和程序的行為直接相關的權限。
這些URI permission的獲取需要content provider(包含那些URI)的配合。強烈推薦在content provider中提供這種能力,並通過android:grantUriPermissions 或者 標簽來聲明支持。
更多的信息可以參考Context.grantUriPermission() , Context.revokeUriPermission() , and Context.checkUriPermission() methods.

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved