Android官方开发指南-系统权限(System Permissions)

系统权限(System Permissions)

Android是一个特权分隔的操作系统,其中每个应用程序运行时带有明显的标识(Linux的用户ID和组ID)。系统中某些部分也被分离成不同的身份。Linux的应用程序与系统应用程序是彼此分开的。

通过“安全”机制提供一个额外的细粒度安全特性,针对一个特定的进程可以强制执行具体的操作限制,并且每个URL提供访问临时访问特定的数据模块的权限。

本文介绍了应用程序开发人员如何使用Android提供的安全功能。在Android开源项目中提供一个更通用的Android的安全概述(Android Security Overview )

安全架构(Securety Architecture)


Android的安全体系结构的一个核心设计是: 默认情况,没有应用程序有权限执行任何对其他应用程序,操作系统,或用户产生不利影响的操作。包括读或写用户的私有数据(如联系人或电子邮件),读或写另一个应用程序的文件,执行网络访问,保持设备苏醒,等等。

因为每个Android应用程序运行在一个进程沙箱中,应用程序必须明确地共享资源和数据。它们通过声明它们需要的不是提供基本的沙箱附加功能的权限来做到这些应用静态声明它们所需要的权限,Android系统会在安装应用时提示用户,以取得用户的同意。Android没有机制来动态地授予权限(在运行时),因为它对用户体验安全性不利。

应用程序沙箱(sandbox)不依赖于用于构建应用程序的技术。尤其Dalvik虚拟机不是一个安全领域,并且任何应用程序都可以运行本地代码(见Android NDK)。所有类型的应用程序-JAVA,native,hybrid,以相同的方式存在于沙箱中,并具有彼此相同程度的安全性。

应用程序签名(Application Signing)


所有的APK(.apk文件)必须用使用由他们的开发者持有的证书的私钥签署。此证书用于标识应用程序的作者。该证书也需要由证书颁发机构签署; 对于Android应用程序使用自签名证书,这是完全允许的。Android证书的目的是为了区分应用程序的作者。这允许系统接受或拒绝应用程序访问的签名级别的权限,也允许系统接收或拒绝应用程序请求给予相同的Linux身份作为另一个应用程序。

用户ID和文件访问(User IDs and File Access)


在安装时,Android的给每个包一个独特的Linux用户ID。在包存在于设备上的时间内,这个身份是保持不变的在不同的装置中,相同的包可具有不同的UID; 重要的是,每个在给定的设备上都有不同的UID。

因为安全强制发生在于进程等级,任何两个包的代码不能正常在同一进程中运行,因为它们需要运行为不同的Linux用户。你可以在AndroidMainfest.xml中的mainfest标签中使用sharedUserID属性来让个包分配相同的用户ID。通过这样做,那时为了安全性这两个包被作为有相同用户ID和文件权限的相同应用。需要注意的是,为了保持安全性,仅具有相同签名(需求相同sharedUserID)的两个应用程序将被给予相同的用户ID。

任何被一个应用程序储存数据都将被分配给该应用程序的用户ID,并且通常不访问其他包。当用getSharedPreferences(String,init) openFileOutput(String,int)  openOrCreateDatabase(String,int,SQLiteDatabase.CursorFactory) 创建一个新文件时你可以使用 MODE_WORLD_READABLE和/或 MODE_WORLD_WRITEABLE标志,允许其他包读/写此文件。设置这些标志时,该文件仍然被你的应用程序拥有,但其全局读取和/或写入权限被设置,以至于任何其他应用程序都可以操作它。

使用权限(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>

在应用程序安装时,应用程序通过安装包请求权限,授予它声明的权限和/或与用户交互基于应用程序的签名检查。当一个应用程序运行时,不再做用户检查。安装应用程序时要么授予特定权限,并根据需要使用此功能,或者此权限不被许可,任何不提示用户就尝试使用此功能都会失败。

很多时候,一个权限失败将导致SecurityException异常被抛出并返回给应用程序。然而,这不能保证发生在任何地方。例如,sendBroadcast(intent)方法检查权限作为数据被传递到每个接收器,该方法调用返回之后,因此,如果有失败的权限,你将不会收到异常。然而,在大多数情况下,一个权限失败将被打印到系统日志。

然而,在一个普通用户的情况(如当应用程序是从Google Play Store安装),如果用户不接受应用程序需求的任一条需求权限,应用程序不能安装所以你一般不必担心因丢失权限运行失败,因为应用程序在安装的时候已经被给予了它所需求的所有权限。

由Android系统提供的权限可以在Manifest.permission找到任何应用程序也可以定义并执行它自己的权限,因此它也不是所有可能权限的综合列表。

应用程序在运行的过程中,在一些地方特定的权限可能被强制执行:

  • 在呼叫进入该系统时,以阻止应用程序执行某些功能。
  • 当启动一个activity时,以防止其他应用程序启动activity。
  • 发送和接收广播,为了控制谁可以接收你的广播或者谁可以发送广播给你。
  • 当访问和操作内容提供者时。
  • 绑定或启动服务。

注意:随着时间的推移,新的限制可能被添加到该平台,为了使用某些API,你的应用程序必须请求先前并不需要权限。由于现有的应用程序假定访问这些API是免费提供的,Android可能应用这些新的权限请求到应用程序的清单文件,以避免破坏新平台版本的应用程序。Android根据targetSdkVersion 属性的值做出决定,应用程序是否可能需要这些权限,如果这个值小于此权限加入的平台版本,那么Android会添加这个权限

例如,在API等级4中新增了 WRITE_EXTERNAL_STORAGE权限,限制访问共享存储空间。如果你的targetSdkVersion 为3或更低,此权限将被在较新的Android版本中添加到您的应用程序。

要注意的是,如果你的应用程序发生这种情况,即使你的应用程序真不需要它们,在Google play上你的应用将会显示这些被需求的权限的列表。

为了避免这种情况,并删除你的应用不需要的默认权限,随时更新你的targetSdkVersion 到尽可能高的版本你可以在Build.VERSION_CODES文档中看到哪些需要添加的权限 

声明和执行权限(Declaring and Enforcing Permissions)


为了执行自己的权限,必须首先在你的AndroidManifest.xml中使用一个或多个<permission>标签来声明它们

例如,应用程序要控制启动它自己的activities的其中一个,就要按下面操作声明权限:

<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>属性是可选的,并且只用于帮助系统给用户显示权限。通常你会想将它设置为一个标准的系统组(被列举在android.Manifest.permission_group中)或更罕见的情况下你自己定义一个。优选使用现有的组,因为这简化了显示给用户的权限UI界面。

需要注意的是为了权限需要提供一个标签和描述。当用户浏览权限列表 ( android:label ) 或者一个单一权限的细节( android:description )时,这些字串资源都会被显示给用户标签要短,简短几句话描述权限所保护的功能的关键部分。描述应该一两句对权限允许持有人做什么的描述​。对于描述我们的规则是两句话,第一描述权限,第二个警告用户如果应用程序允许一个权限会有下面是一个关于CALL_PHONE权限的标签和描述的例子

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

权限一般在定义系统中,你可以通过设置应用和adb shell pm list permissions shell命令看到。使用设置应用进入到设置中的应用程序菜单。选择一个应用,并向下滚动,就能看到应用程序所使用的权限。对于开发者来说,adb "-S" 选项显示权限形式类似于下面这样:

$ adb shell pm list permissions - s 
All Permissions :

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

...

执行AndroidMainfest.xml中的权限

你可以通过应用的AndroidMainfest.xml限制访问系统整个组件或应用程序的高级权限,所有这些要求包含所需求组件的一个android:permission属性,为这个权限命名,以后就可以用来控制访问它。 

Activity权限(应用于<activity>标签)限制谁可以启动相关的activity。在Context.startActivity()Activity.startActivityForResult()时,权限会被检查; 如果调用者不具备所需的权限,然后SecurityException异常会被调用抛出。

Service权限(应用于<Service>标签)限制谁可以启动或绑定到相关的服务上。Context.startService() Context.stopService() Context.bindService()时权限会被检查; 如果调用者不具备所需的权限,然后SecurityException 异常被调用抛出。

BroadcastReceiver权限(应用<Receiver>标签)限制谁可以发送广播到相关的接收器。在 Context.sendBroadcast()返回后,权限会被检查。因为系统会尝试发送已提交的广播给被给定的接收器。其结果是,权限失败不会导致抛出异常返回给调用者; 它只是无法实现意图。同样的方式,权限可以供给Context.registerReceiver() 以控制谁可以广播到一个编程时注册的接收者。另一个种方式,在调用ontext.sendBroadcast(),权限被提供用来限制能接受这个广播的BroadcastReceiver对象(见下文)。

ContentProvider权限(应用于<ContentProvider>标签)限制谁可以访问ContentProvider中的数据Content providers能调用URL权限是重要的,额外安全的,便利可用的,这在后面再描述)。不同于其他组件,ContentProvider有两个独立的权限属性,你可以设置: android:readPermission 限制谁可以从提供者中读取和 设置Android:writePermission限制谁对他进行写操作。需要注意的是,如果一个提供者的数据被读写权限所保护,你仅持有写的权限并不意味着你能读取一个提供者的数据。当你第一次检索提供者和对这个提供者的数据进行操作(如果你没有任何权限,就会抛出SecurityException异常)时,权限会被检查。使用 ContentResolver.query()需要持读取权限; 使用 ContentResolver.insert() ContentResolver.update()  ContentResolver.delete() 需要写入权限。在所有这些情况下,不持有所要求的权限就会在调用的时候导致 SecurityException 异常抛出

发送广播时,执行权限(Enforcing Permissions when Sending Broadcasts)

对于权限,除了执行谁可以发送Intent到已注册的BroadcastReceiver(如上所述)之外,您也可以在发送广播时指定所需的权限。通过调用有权限字符串的Context.sendBroadcast(),你需要一个接受者的应用程序也必须持有此权限,这样你才能接收你发送的广播。

注意,广播接收者和播放发送者都需要权限,这样,为了传递给相关对象的Intent,两个权限都必须检查通过。

其他权限的执行(Other Permission Enforcement)

在调入一个service的过程中任意微妙的权限都会被执行。这是通过Context.checkCallingPermission() 方法来完成的。调用的时候使用一个所需要的permission string,返回给调用方法一个整数判断是否具有相关权限。需要注意的是这种情况只能发生在来自另一个进程的调用,通常是一个service发布的IDL接口或者是其他方式提供给其他的进程。

还有一些其他有用的方法来检查权限。如果你有另一个进程的PID,您可以使用上下文方法Context.checkPermission(String,int,nit) 来检查针对此PID的权限。如果您有其他应用程序包的名称,你可以使用直接的PackageManager方法PackageManager.checkPermission(String,String)判断特定的包是否已授予特定权限。

URI权限


到目前为止我们讨论的标准的权限系统对于内容提供者来说是不够的。一个内容提供者可能想保护它的读写权限,而同时与它对应的直属客户端也需要将特定的URI传递给其它应用程序以便对该URI进行操作。一个典型的例子是邮件应用程序的附件。访问邮件需要使用permission来保护,因为这些是敏感的用户数据。然而,如果有一个指向图片附件的URI需要传递给图片浏览器,那个图片浏览器是不会有访问附件的权利的,因为它不可能拥有所有的邮件的访问权限。


针对这个问题的解决方案就是per-URI permission:当启动一个activity或者给一个activity返回结果的时候,调用方可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION。这赋予接收活动(activity)访问该意图(Intent)指定的URI的权限,而不论它是否有权限进入该意图对应的内容提供者。


这种机制允许一个普通的功能式模型,在这种机制中,用户交互(如打开一个附件, 从列表中选择一个联系人)驱动特设的细微权限的授与。这是实现减少应用程序所需要的权限而只留下和程序行为直接相关的权限时很关键的一步。


然而,这些URI权限的获取需要持有这些URLs的内容提供者来配合。强烈建议在内容提供者中实现这种功能,并通过 android:grantUriPermissions 或者<grant- uri-permissions>标签来声明支持。

更多的信息可以参考 Context.grantUriPermission() , Context.revokeUriPermission()函数。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值