本文档描述了应用程序开发人员可以使用Android提供的安全特性。一个更普遍的Android安全性概述是在Android开源项目提供。
Android是一个privilege-separated操作系统,每个应用程序不同的系统中运行身份(Linux用户ID和组ID)。系统的部分也分为不同的身份。Linux从而互相隔离应用程序和系统。
额外的细粒度安全特性通过“许可”(permission)机制,将强制执行的具体操作限制在一个特定的进程执行,并且提供每个URI权限给予临时访问特定的数据块。
安全架构
Android安全架构的核心设计点是没有应用程序,默认情况下,允许执行任何操作,将会严重影响其他应用程序,操作系统或用户。这包括读写用户的私人数据(如联系人或电子邮件),阅读或写作的另一个应用程序的文件,执行网络访问,保持设备清醒,等等。
因为Android沙箱应用程序,应用程序必须显式地共享资源和数据。为此,他们宣布他们不需要额外功能的权限提供的基本沙箱。应用静态声明它们需要的权限,和同意的Android系统提示用户安装的应用程序。安卓没有授予权限动态机制(在运行时),因为它复杂的损害用户体验安全。
应用程序沙箱不依赖于用于构建应用程序的技术。尤其是Dalvik虚拟机不是一个安全边界,任何应用程序可以运行本地代码(看到Android NDK)。所有类型的应用程序 - Java中,本地和混合 - 被沙盒以同样的方式和彼此具有相同的安全性。
应用签名
所有的Android应用程序(.apk文件)必须与证书的私钥签署了他们的开发人员。这个证书标识应用程序的作者。证书不需要签署的证书颁发机构:它是完全允许的,和典型的Android应用程序使用自签名证书。证书在Android的目的是区分应用程序作者。这允许系统授予或拒绝signature-level应用程序访问权限和应用程序授予或拒绝'srequest给予相同的Linux身份另一个应用程序。
用户ID和文件访问
在安装时,Android给每个包一个截然不同的Linux用户ID。包的身份期间保持不变的生活设备。在一个不同的设备,同样的包可能有不同的UID;重要的是,每个包都有一个独特的UID给定的设备上。
因为安全执法发生在流程级别,任何两个包的代码不能正常运行在同一进程中,因为他们需要运行不同的Linux用户。您可以使用在AndroidManifest sharedUserId属性。xml清单标签的每个包分配相同的用户ID。这样做,为了安全的两个包被视为相同的应用程序中,使用相同的用户ID和文件权限。注意,为了保持安全,只有两个应用程序使用相同的签名,请求相同的sharedUserId)将获得相同的用户ID。
任何数据存储的应用程序将被指派该应用程序的用户ID,而不是通常可以访问其他包。当创建一个新文件与getSharedPreferences(字符串、整数),openFileOutput(字符串、整数),或openOrCreateDatabase(字符串、整数SQLiteDatabase.CursorFactory),您可以使用MODE_WORLD_READABLE和/或MODE_WORLD_WRITEABLEflags允许其他包读/写文件。设置这些旗帜时,文件仍然是属于您的应用程序,但是其全球读和/或写权限已设置适当的任何其他应用程序可以看到它。
使用权限
一个基本的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(意图)方法检查权限数据被送到每一个接收器,在方法调用返回后,你将不会收到一个例外如果有权限失败。在几乎所有情况下,一个权限失败将打印系统日志。
安卓系统可以提供的权限在Manifest.permission找到。任何应用程序也可以定义和执行自己的权限,所以这不是一个详尽的列表所有可能的权限。
特定的权限可以执行在许多地方在你的程序的操作:
1.打电话的时候进入系统,防止一个应用程序执行某些功能。
2.当开始一个活动,防止应用程序启动其他应用程序的活动。
3.同时发送和接收广播,控制谁能收到你或你可以发送一个广播播出。
4.当访问和操作在一个内容提供者。
5.绑定或开始一个服务。
声明和实施许可 (Permissions)
执行自己的权限,您必须首先在AndroidManifest.xml声明它们使用一个或多个<permission>标记。
例如,一个应用程序想要控制谁可以启动一个活动可以宣布允许此操作如下:
<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 >属性是可选的,用于帮助系统权限显示给用户。通常你会想将这个标准系统组(inandroid.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 command “adb shell pm list permissions”。使用应用程序的设置,设置>应用程序。使用Settings app Settings > Applications。选择一个应用程序和向下滚动查看权限的应用程序使用。对于开发人员来说,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
...
在AndroidManifest.xml中执行权限
高级权限限制访问整个系统或应用程序的组件通过AndroidManifest.xml可以应用。这需要的是包括一个 android:permission 属性所需的组件,命名的权限将被用来控制对它的访问。
Activity权限(应用于<activity>标记)限制谁可以开始相关的活动。权限检查期间Context.startActivity()和Activity.startActivityForResult();如果调用者没有所需的许可会在调用时抛出SecurityException。
Service权限(应用于<service>标记)限制谁可以启动或绑定到相关的服务。权限检查期间Context.startService(),Context.stopService()和Context.bindService();如果调用者没有所需的许可会在调用时抛出SecurityException。
BroadcastReceiver权限(应用于<receiver>标记)限制谁可以发送广播相关的接收机。权限检查后Context.sendBroadcast()返回,因为系统试图将提交的广播接收器。因此,允许失败并不会导致一个异常被抛出回调用者;它将不交付的意图。同样的,可以提供给Context.registerReceiver许可()来控制谁可以广播以编程方式注册接收机。走的是另一条路线,可以提供许可当调用Context.sendBroadcast()来限制BroadcastReceiver对象允许接收的广播(见下文)。
ContentProvider权限(应用于<provider>标记)在于ContentProvider限制谁可以访问数据。(内容提供商有一个重要的附加安全设施可用calledURI权限描述。)不同于其他组件,有两个独立的权限属性可以设置:android:readPermission限制谁可以阅读从提供者,andandroid:writePermission限制谁可以写。注意,如果一个提供者是受保护的读和写权限,只持有写权限并不意味着你可以阅读从一个提供者。权限检查当你第一次检索提供者(如果你没有权限,将抛出抛出SecurityException),当你在提供者执行操作。UsingContentResolver.query()需要的读权限;使用ContentResolver.insert(),ContentResolver.update(),ContentResolver.delete()需要写权限。在所有这些情况下,而不是持有所需的权限导致抛出SecurityException。
发送广播时实施许可
除了允许执行谁能给注册BroadcastReceiver的Intent(如上所述),您还可以指定一个发送一个广播时所需的权限。通过callingContext.sendBroadcast()允许字符串,你要求接收机的应用程序必须持有许可以收到你的广播。
注意,接收机和广播需要许可。当这一切发生的时候,这两个权限检查必须通过意图的传递给相关的目标。
其他权限实施
任意细粒度的权限可以执行在任何调用一个服务。这是完成theContext.checkCallingPermission()方法。调用所需的字符串,它将返回一个整数表示许可是否许可被授予当前调用进程。注意,这只能用当你执行一个电话来自另一个过程中,通常通过一个IDL接口发布从服务或以其它方式给另一个进程。
有许多其他有用的方法来检查权限。如果你有另一个进程的pid,您可以使用上下文方法上下文。checkPermission(String,int,int)检查权限对pid。如果你有另一个应用程序的包名,您可以使用直接PackageManager methodPackageManager。checkPermission(String,String)来找出特定的包是否被授予特定的权限。
URI许可
到目前为止所描述的标准许可系统使用内容提供者时往往是不够的。一个内容提供者可能想保护自己的读和写权限,而其直接客户也需要手特定uri到其他应用程序操作。一个典型的例子是在邮件附件的应用程序。访问权限的邮件应该受到保护,因为这是敏感的用户数据。但是,如果一个URI图片附件给一个图像浏览器,图像查看器将没有权限打开附件,因为它没有理由允许访问所有电子邮件。
这个问题的解决方案是per-URI权限:当开始一个活动或返回一个活动的结果,调用者可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION和/ orIntent.FLAG_GRANT_WRITE_URI_PERMISSION。这种资助接收活动许可访问特定的数据URI的意图,不管是否有权限访问数据相对应的内容提供者的意图。
这种机制允许一个公共capability-style模型,用户交互(打开附件,从列表中选择一个联系人,等)驱动特别授予的细粒度的权限。这可能是一个关键设施减少应用程序所需的权限只有那些与他们的行为直接相关。
然而,URI的细粒度权限确实需要一些合作内容提供商持有这些URI。强烈建议内容提供商实现这个设施,并宣布他们支持通过android:grantUriPermissions属性或< grant-uri-permissions >标记。
更多的信息可以看Context.grantUriPermission(),Context.revokeUriPermission(),和Context.checkUriPermission()方法。