Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android開發指南-框架主題-安全和許可

Android開發指南-框架主題-安全和許可

編輯:Android開發實例

安全和許可Security and Permissions

    Android是一個多進程系統,每個應用程序(以及系統的部分)運行在它自己的進程裡。大多數程序和系統之間的安全性通過基礎的Linux機制在進程級別進行支持,如分配給應用程序的用戶和群組IDs。更多細化的安全特性通過“許可”機制來提供,它實施對一個進程能夠執行的特定操作方面的限制,和對於每個URI的特定數據段的特許訪問的授權。

 

安全架構Security Architecture

    Android安全架構中的一個設計要點是在默認情況下應用程序沒有權限執行對其它應用程序、操作系統或用戶有害的操作這些操作包括讀/寫用戶的隱私數據(例如聯系方式或e-mail),讀/寫其它應用程序的文件,執行網絡訪問,保持設備激活,等等

    應用程序的進程是一個安全的沙箱。它不能干擾其它應用程序,除非明確聲明它需要額外的基本的沙箱不能提供的功能的許可權。這些許可權請求能夠被不同方式的操作所處理,常見的是基於證書和用戶提示的自動允許或禁止。應用程序的權限請求被聲明為靜態的,這樣後面在安裝時能夠知道它們而且不會被改變。

 

應用程序簽名Application Signing

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

 

用戶IDs和文件訪問User IDs and File Access

    每一個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), 或者openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory)來創建一個新文件時,你可以通過使用MODE_WORLD_READABLE與/或MODE_WORLD_WRITEABLE標志位來設置是否允許其他package來訪問讀寫這個文件。當設置這些標志位時,該文件仍然屬於該應用程序,但是它的全局讀寫權限已經被設置,使得它對於其他任何應用程序都是可見的。

 

使用許可Using Permissions

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

例如,一個想要監控接收短消息的應用程序需要指定:

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

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

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

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

一個特定的許可可能會在你的程序操作過程中的很多地方都被實施:

  • 當系統有來電的時候,用以阻止程序執行其它功能。
  • 當啟動一個活動(activity)的時候,會阻止應用程序啟動其它應用程序的Acitivity。
  • 在發送和接收廣播的時候,去控制誰可以接收你的廣播或誰可以發送廣播給你。
  • 當進入並操作一個內容提供器(content provider)的時候
  • 當綁定或起動一個服務(service)的時候
 

聲明和實施許可Declaring and Enforcing Permissions

    為了實施你自己的permissions,你必須首先在AndroidManifest.xml文件中聲明該permissions.通常我們通過使用一到多個<permission> tag來進行聲明。

 例如,一個應用程序想要控制誰能啟動它的活動,可以為該操作聲明許可如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.me.app.myapp" >
 
    <permission android: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>屬性是可選的,只是用於幫助系統顯示許可permission給用戶(實際是告知系統該許可是屬於哪個許可組permission group的)。你通常會選擇使用標准的system group來設定該屬性,或者更為少見的用你自己定義的group。推薦使用一個已經存在的group,因為這樣UI給用戶顯示許可的時候會更簡單。

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

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="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。

 

 在清單文件裡實施許可Enforcing Permissions in AndroidManifest.xml

    用於限制進入系統或應用程序的Components的高級別許可可以再AndroidManifest.xml中實現.所有這些都可以通過在相應的component中包含 android:permission 屬性,命名該permission以使其被用以控制進入的權限。

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

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

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

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

 

發送廣播時實施許可Enforcing Permissions when Sending Broadcasts

    除了之前說過的Permission(用於限制誰才可以發送廣播給相應的BroadcastReceiver),你還可以在發送廣播的時候指定一個permission。在調用Context.sendBroadcast()的時候使用一個permission string,你就可以要求receiver的宿主程序必須有相應的permission。

    值得注意的是Receiver和broadcaster都可以要求permission。當這種情況發生時,這兩種permission檢查都需要通過後才會將相應的intent發送給相關的目的地。

 

其他權限實施Other Permission Enforcement

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

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

 

URI許可URI Permissions

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

   針對這個問題的解決方案就是per-URI permission: 當啟動一個activity或者給一個activity返回結果的時候,呼叫方可以設置Intent.FLAG_GRANT_READ_URI_PERMISSION和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION。這賦予接收活動(activity)訪問該意圖(Intent)指定的URI的權限,而不論它是否有權限進入該意圖對應的內容提供器。

    這種機制允許一個通常的能力-風格(capability-style)模型,以用戶交互(如打開一個附件, 從列表中選擇一個聯系人)來驅動細化的特別授權。這是一個很關鍵的能力,可以減少應用程序所需要的權限,只留下和程序行為直接相關的權限。

    這些URI permission的獲取需要內容提供器(包含那些URI)的配合。強烈推薦在內容提供器中實現這種能力,並通過android:grantUriPermissions或者<grant-uri-permissions>標簽來聲明支持。

    更多的信息可以參考Context.grantUriPermission(), Context.revokeUriPermission()和Context.checkUriPermission()方法。

轉載於http://blog.csdn.net/iefreer/archive/2009/09/10/4537371.aspx

官方文檔原文http://androidappdocs.appspot.com/guide/topics/security/security.html

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