声明:html
本文由Gordon翻译android
公布于www.dlvoice.comshell
欢迎转载,但请保留此声明api
原文地址:http://developer.android.com/guide/topics/security/permissions.html浏览器
Android是一个特权分离的操做系统。执行在其上的应用都有一个特定的系统身份(Linux的用户ID和组ID)。系统的部分也会被分为特定的身份,Linux就是经过这个身份来差异各个应用的。安全
更加具体的安全特性是经过“权限”机制来控制一个进程的特定操做可否够运行。网络
它经过每一个URI的权限来来决定他们可否够訪问特定的数据。架构
本文将会介绍开发人员怎样使用Android提供的安全特性。更基础的文章“Android Security Overview”可以在Android的开源项目中查看。app
Android安全架构设计的核心理念就是没有一个应用可以破坏另一个应用。操做系统或者用户。这包含读写用户的私有数据(比方联系人和email)。读写另一个应用的文件,进行网络訪问。保持设备一直醒着或者别的操做。ide
因为每一个应用都是工做在进程封装上。因此它必须明白地分享资源和数据。他们可以经过声明他们需要的权限来实现资源和数据的共享。
应用静态声明他们的权限。而后系统在安装应用的时候请求用户容许应用得到这些权限。
应用的封装并不是由编译应用的技术来决定的,Dalvik虚拟机(VM)并不是一个特殊安全的界限,每一个应用都可以执行本地的代码(參考Android NDK)。每一种类型的应用——Java,本地以及混合的——他们都是用相同的方式来进行封装的,并且他们的安全等级也是同样的。
所有的APK文件都必须进行签名,而且签名使用的是包括开发人员私有密钥的证书。
这个证书指明了应用的做者。这个证书并不需要一个证书认证来进行签名。
一般来讲。Android的应用使用一个自签名的证书就足够了。
证书的目的就是为了区分应用的做者。这就使得系统可以推断应用可否够訪问签名级别的权限,以及是否赞成别的应用和这个应用使用相同的Linux身份(ID)。
在安装的时候,Android给每个包一个固定的Linux用户ID。同一设备上这个ID将会伴随这个包一辈子。固然不一样设备上,同一个应用包可能会有不一样的用户ID。
不管如何在特定的设备上每个包都有一个特定的UID。
因为安全相关的操做都是在进程级进行执行的,不论什么两个应用包的代码不能在同一进程执行,因为他们需要在不一样的Linux用户上进行执行。若你想两个应用使用相同的用户ID执行,仅仅要设置AndroidManifest.xml文件的manifest标签中的sharedUserId属性相同就能够。
这样作了以后,在安全层面来看。这两个应用将会被以为是同一个应用,具备相同的用户ID和文件权限。
注意,仅仅有两个使用相同签名的应用(固然SharedUserID也得相同)才会给予相同的用户ID。
应用存储的不论什么数据都应当指定为这个应用的用户ID,并且不能被别的应用包訪问。当使用getSharedPreferences(String, int), openFileOutput(String, int)或者openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory)建立文件时,你可以使用MODE_WORLD_READABLE或者MODE_WORLD_WRITEABLE标志来赞成别的应用对这个文件的读写。当这些标志被设置以后,这个文件仍然是属于你的应用,但是他的全局读写权限将会被设置。从而让别的应用可以使用它。
一个主要的Android应用默认来讲是没有相关权限的。这也就意味着它不能作不论什么破坏用户体验及设备数据的操做。
为了保护设备的特性。你必须在AndroidManifest.xml文件里声明一个或者多个<uses-permission>标签。
好比。一个需要监听SMS信息的应用应当设定例如如下:
在应用安装的时候,应用所请求的权限(用户的签名和声明时肯定的)会在包安装的时候让用户赋予给应用。应用在执行的时候,就不会再让用户进行检查了,应用要不在安装的时候被赋予特定的权限。从而可以使用对应的特性,要不就没有使用相关特性的权限。
一般状况下。如果权限失败将会致使一个SecurityException发送给应用。但是并不是在不论什么地方都会产生这个exception。举例来讲,sendBroadcast(Intent)方法因为要把数据发送给每一个receiver,在这种方法返回的时候它会检查他们的权限,但是如果有权限的失败。你不会收到exception。
固然。差点儿所有的权限失败的状况。都会被打印到系统log中。
然而,正常用户使用的状况下(比方应用从Google应用商店里安装),如果用户不一样意应用申请的权限。这个应用就不会被成功安装。因此。通常来讲你没有必要操心执行时缺乏权限。因为其实你的应用在安装的时候就已经得到了它想要的对应权限。
Android系统提供的权限可以參考Manifest.permission文件。不论什么应用也都有可能定义并支持它本身的权限。因此这个列表也不能包括所有的可能权限。
注意:
随着时间的推移,平台可能会添加新的权限要求。因此为了使用特定的API,你的应用需要请求一些以前不用请求的权限。因为已经存在的应用可能以为訪问这些API是直接可用的。Android可以在应用的manifest文件里直接申请新的权限请求从而避免在新的平台版本号上破坏原有的应用。
Android做出应用可能需要权限的描写叙述是基于targetSdkVersion属性的。假如这个的值小于权限假如的版本号。那么Android就添加相应的权限。
举例来讲,WRITE_EXTERNAL_STORAGE权限是在API级别4中增长的。它是为了防止訪问共享的存储空间。
假如你的targetSdkVersion小于3,那么在新的Android版本号中会把这个的权限增长到你的应用中。
需要注意的是,假如这样的状况在你的应用中发生,即便这些权限在你的应用中可能没有真正地请求。Google应用商店也会在显示你的应用的时候请求这些权限。
为了不这样的状况发生,你需要及时把你的targetSdkVersion更新到足够高的版本号。
你可以參考Build.VERSION_CODES文档来看每次公布都增长了哪些权限。
为了实施你的权限,你需要首先在AndroidManifest.xml文件里使用<permission>标签来声明他们。
好比,一个应用想要控制谁可以启动它的activity,就应当为这个操做声明一个权限,详细的方法例如如下:
<protectionLevel>属性是需要的。它是用来告诉系统应用需要这个权限的时候是怎样来通知用户的,或者谁是被赞成获得这个权限的。详细的描写叙述可以參考连接的文件。
(译者注:后期翻译ok会增长)。
<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>
你可以经过设置应用和shell命令“adb shell pm list permissions”来查看当前系统定义的权限。如果使用设置应用,可以在设置->应用如下进行查看。
选取一个用户。向下滚动,可以看到应用使用的权限。
对开发人员来讲,adb –s的选项将会以用户看到的形式来显示相应的权限:
高级别的权限会限制訪问系统的整个组件。应用可以经过AndroidManifest.xml文件得到。所有的这些请求都包括在相关组件的android:permission属性中,它会命名控制訪问的权限名。
Activity权限(<activity>标签)限制了谁可以訪问相应的activity。
这个权限是经过Context.startActivity()和Activity.startActivityForResult()进行检查的。假如调用者没有这个权限,那么就会产生一个SecurityException。
Service权限(<service>标签)限制了谁可以启动和绑定相应的service。
这个权限是经过Context.startService()。Context.stopService()以及Context.bindService()来检查的。假如调用者没有这个权限,相同会产生一个SecurityException。
BroadcastReceiver权限(<receiver>标签)限制了谁能向相关的receiver发送广播。这个权限是在Context.sendBroadcast()以后检查权限的,因为这个时候系统会把广播发送给特定的接受者。这样一来,权限的失败将不会产生一个exception返回给调用者,他仅仅会不发送intent而已。相同的。权限可以经过Context.registerReceiver()来控制谁可以广播给一个经过程序注冊的receiver。还有一方面,当调用context.sendBoradcast()的时候也会提供权限来限制哪个BoradcastReceiver对象可以接收这个广播。
(详情见如下)
ContentProvider权限(<provider>标签)限制了谁可以訪问ContentProvider的数据。(Content provider另外一个重要的额外可用的安全机制称之为URI权限,这个会在稍后进行介绍)。
和别的组件不一样,这里有两个独立的权限属性可以设置:android:readPermission限制了谁可以读这个provider,android:writePermission限制了谁可以写它。
注意,provider是由读写权限分别保护的,得到些权限不意味着你可以读。
这个权限是在你第一次检索provider进行检查的(假如你没有权限,一个securityException将会抛出)。固然你在这个provider上进行操做的时候也会检查对应的权限。
可以使用ContentResolver.query()函数来请求获得读的权限,使用ContentResolver.insert()。ContentResolver.update(), ContentResolver.delete()来请求写的权限。在所有这些状况中。如果没有获得对应权限都会抛出一个SecurityException。
除了上文提到的对于注冊过的BroadcastReceiver发送intent的时候运行权限以外,你还可以在发送广播的时候请求权限。在调用Context.sendBroadcast()的时候。增长一个权限字符串,你就可以要求这个接收的应用必须有响应的权限才干接收广播。
注意,发送者和接收者都可以请求权限。
这样的状况下,在发送intent和接收端都需要进行对应的权限检查。
更细的权限会在调用service时运行。这个是经过Contex.checkCallingPermission()方法来实现的。在调用这种方法的时候传入一个权限字符串,就会返回一个整形值用来表示当前的进程是否已经得到了相应的权限。
注意,这个仅仅会在别的进程运行一个调用才会被使用。一般来讲是经过一个service的IDL接口或者提供给别的进程的其它方法来实现。
另外一些别的方式来检查权限。假如你有另外进程的pid,你可以使用Context.checkPermission(String, int, int)来检查相应的权限。
假如你有别的应用的包名字。你可以使用PackageManager.checkPermission(String, String)来检查相应的包是否得到相应的权限。
到眼下为止所描写叙述的标准的权限系统对content providers的使用来讲都不是很是好。
content provider可能想要保护它本身的读写权限,尤为是当它的直接使用者对别的应用操做获取特定的URI的时候。一个典型的样例就是邮件应用中的附件。邮件的訪问需要权限进行设置。因为毕竟用户的数据是敏感的。然而,假如图片浏览器得到了一个图片附件的URI。这个图片浏览器将不会有打开图片的权限,因为它没有道理去得到訪问邮件的权限。
这个问题的解决方法就是每一个URI的权限:当启动一个activity或者返回一个结果给activity的时候,调用者可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION或者Intent.FLAG_GRANT_WRITE_URI_PERMISSION。这个赞成接收activity得到訪问intent中特殊数据URI的权限。而不用管他是否有权限訪问这个Intent提供者的数据权限。
这个机制赞成了一个用户交互时(打开一个附件,选择一个联系人等)对专用的更细的权限訪问的通用模型。
这将会是下降应用需要权限的一个关键所在。应用仅仅需要那些他们特性直接相关的权限就能够。
然而对细粒度URI权限的获取,需要这些URI的content provider也要作一些对应的操做。咱们推荐这些content provider实现这个功能,他们仅仅需要经过android:grantUriPermissions属性或者<grant-uri-permissions>标签来声明就能够。
不少其它的资讯请參考Context.grantUriPermission(),Context.revokeUriPermission()和Context.checkUriPermission()方法。
推荐您继续阅读下面内容:
Permission that Imply Feature Requirements
关于怎样经过请求权限来限制你的应用仅仅在包括相应硬件或者软件特性的设备上执行。
<uses-permission>
Manifest标签下的API參考,他声明了应用需要的系统权限。
Manifest.permission
所有系统权限的API參考。
下面内容你可能也感兴趣:
关于Android在不一样类型设备上执行的资讯,他会介绍怎样针对不一样设备进行优化你的应用以以及怎样在不一样设备上执行你的应用。
Android Security Overview
更具体的关于Android平台的安全模式。