1.3 SystemPermissions

来源:互联网 发布:oracle分布式数据库 编辑:程序博客网 时间:2024/06/05 16:09

SystemPermissions

       Android是一种权限分离的操作系统,每一个应用运行的时候都有独特的系统标识(System identity, Linux user ID and group ID)。系统的部分同样也分离称为不同的identity。Linux从而就能将应用从系统分割出来,同时不同的应用也独立于其他的系统。

       通过“权限”机制(permission)可以添加上finer-security的特征,这样可以强制限制一些特殊的执行某个线程的操作。

       该文档说明开发者如何使用android提供的安全功能。A more general AndroidSecurity Overview is provided in the Android Open Source Project.

 

Security Architecture

       Android安全体系的中心设计是无应用程序,默认情况下,它允许任何可以严重影响其他应用,系统和用户的操作。这包括可以读写用户的私有数据(例如联系人或邮件),读写其他应用的文件,执行网络访问,保持设备的启动状态等。

       因为每个android应用都在一个沙箱线程中操作,应用必须明确的共享资源和数据。它们不是通过基础沙箱(basic sandbox)的允许获得额外的功能,而是通过声明他们需要的权限来获得。应用静态的声明它们需要的权限,android系统则会在app安装的时候提醒用户给予许可。Android没有动态给予权限的机制(即在app运行期间提醒用户给予许可),因为它扰乱了用户体验,也损害安全。

       应用程序的安全沙箱并不依赖于创建程序的技术。特别的,Dalvik VM并不是安全边界,任何app都可以运行源代码(参照Android NDK)。所有类型的代码——Java,源代码,混合代码都是安全沙箱,同时他们各自都有相同程度的安全性。

 

Application Signing

       所有的apk都必须用证书签署,该证书的私有秘钥为开发者所有。该证书能识别应用程序的作者。该证书不需要证书颁发机构来签署,它对于android应用程序来说是被完全允许的典型的自签名证书。在android中使用证书签署的主要目的是为了区分app的作者。使用证书使得系统可以通过signature-levelpermission同意或者拒绝应用访问,同时也可以授予或者拒绝一个应用程序请求给予另一个应用程序相同的Linux ID。

 

User IDs and File Access

       在安装的时候,android会给每个apk一个独特的Linux user ID。在apk文件存在于设备期间,这个ID是一个常量。在不同的设备上,同一个apk文件可能会有不同的UID。重要的是,每个apk在设备上有独一无二的UID即可。

       因为安全实施实在线程水平上发生的,任何两个apk的代码不能在同一个线程上运行,因为他们必须在两个不同的Linux账户下运行。你可以在两个apk的AndroidManifest.xml文件中使用sharedUserId标签指定他们使用相同的user ID。这样做,从安全目的上看,这两个apk已经被处理为相同的程序,拥有相同的user ID和文件权限。要注意的是,为了保证安全性,只有两个应用程序使用相同的签名(同时要求相同的sharedUserId)才会被给予相同的user ID。

      任何被应用程序存储的数据都会被指派该程序的user ID,并且在通常情况下不能访问其他包。当使用getSharedPreferences(String int),openFileOutput(Stringint),或者是openOrCreateDatabase(Stringint, SQLiteDatabase.CursorFactory)方法来创建一个新的文件的时候,你可以使用MODE_WORLD_READABLE或者MODE_WORLD_WRITEABLE标记允许其他apk读写这个文件。当设置这些标记的时候,文件依然归你的应用所有,但是它已经被设置了全局读写许可,所以任何别的应用都可以看到它。

 

Using Permission

       一个基本的android应用程序默认设置为没有权限与之关联,这意味着它不会做任何事情来破坏用户体验,也不会危害设备上的其他数据。为了使用设备上的受保护的功能,你需要在你的AndroidManifest.xml文件中使用一个或多个<uses-permission>标签声明你的app需要的权限。例如,一个app需要监听收到的短信,可以如下声明:

<manifest xmls: android=http://schemas.android.com/apk/res/android

package=”com.android.app.myapp”>

       <uses-permissionandroid:name=”android.permission.RECEIVE_SMS”/>

</manifest>

 

在app安装的时候,app需要的权限可以被用户同意而获得。

       在通常情况下,SecurityException会将获取权限失败抛回给app。但是,这并不能保证每次都会发生。例如,sendBroadcast(Intent)方法在数据传递给每一个接受者的时候检查权限,该方法执行后会直接return,所以即使发生了permissionfailures你也不会收到任何报错。在几乎所有情况下,permission failure会在系统日志中被记录下来。

       但是在正常情况下,(用户通过Google Play Store安装app)app在没有获得用户相关权限批准的情况下是无法安装的,所以无须担心运行时的报错。

       一个特定的权限可能可以在你的程序操作中的许多地方执行:

●       在有电话进入的时候,可以通过执行某些功能阻止一个程序

●       当启动一个程序的activity的时候,可以通过启动其他程序的activity阻止该程序

●       当同时发送和接受到广播的时候,可以控制你发送广播给谁,也可以控制你从谁获得广播

●       访问或操纵一个contentprovider的时候

●       绑定或发送service的时候

 

注意:有时候会有一些新的限制添加在android平台上,为了使用该平台相应的API你的app可能会需要添加先前并不需要的权限。例如,WRITE_EXTERNAL_STORAGE权限是在API level4的时候添加的,目的是为了限制访问共享存储空间。如果你的targetSdkVersion是3或者更低,则在新版本的android上你的app会被添加上这个权限。需要注意的是,如果上述情况发生在你的app上,Google Play Store清单上的你的app会请求获得这些新增的权限,即使你的app其实根本不需要它们。为了避免这种事件的发生,移走这些你不需要的默认权限设置,尽可能的及时更新你的targetSdkVersion。你可以在文档Build.VERSION_CODES中查看每个版本里新增的权限。

 

Declaring and Enforcing Permissions

       为了定义你自己app的权限,首先你需要在AndroidManifest.xml文件中使用一个或多个<permission>标签。

       例如,一个app希望控制由谁来开始它的其中一个activity,那么可以为这个操作如下声明权限:

<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>是必须的,这个标签告诉系统如何用来通知用户该app需要权限的等级,或者谁有权利持有这个权限。标签<permissionGroup>是可选择的,仅仅在系统展示权限给用户的时候使用。你通常会在一个标准系统组(列入android.Manifest.permission_group)或者在你自己定义的这种更少见的情况下见到这个标签。实际上我们更倾向于使用一个已经存在的组,例如一个简化的UI将权限展示给用户。

(插播:uses-permission是系统已经定义好的权限,而permission是我们自己给自己的app定义的权限,基本很少使用,只有在我们自己的app的一些数据需要被别的app访问的时候才会定义permission以及相应的label,然后别的app使用uses-permission添加上我们的标签即可访问我们app的数据)

注意上面的标签和描述的内容是展示给用户看的,他们会看到权限的列表(android: label)或者一个单独的权限的细节(android:description)。标签要简短,使用几个词描述该权限保护的功能的关键字。描述部分可以包含几句话,用于描述该权限允许用户做什么。我们建议使用两句话,第一句话描述权限,第二句话警告用户如果该权限被同意之后可能发生什么糟糕的事情。

例如下面是CALL_PHONE权限的标签和详细描述:

<string name=”permlab_callPhone”>directlycall phone numbers</string>

<string name=”permdesc_callPhone> Allowsthe application to call phone numbers without your intervention. Maliciousapplication may cause unexpected calls on your phone bill. Note that this doesnot allow the application to call emergency numbers. </string>”

       你可以在系统中的设置应用中查看当前定义的权限,也可以使用shell命令 adb shell pm list permissions -s来查看。使用Settings来查看直接Settings à Apps à 选择需要查看的app,一般权限描述会在最下方。对于开发者而言,可以直接问使用shell命令查看

 

Enforcing Permissions in AndroidManifest.xml

       通过你的AndroidManifest.xml可以应用那些限制系统或者应用程序的所有组件的高级权限。所有需要使用这些高级权限的组件需要包含 android: permission 属性,同时命名这个权限以便控制对该组件的访问。

       Activitypermission(在<activity>标签中应用)限制谁可以启动这个activity。在方法Context.startActivity()和Activity.startActivityForResult()中会检查权限,如果调用者没有该activity要求的权限,则会抛出SecurityException。

       Servicepermission(在<service>标签中应用)限制谁可以启动或者绑定该service。在方法Context.startService(),Context.stopService()和Context.bindService()中会检查权限,如果调用者没有该service要求的权限,会抛出SecurityException。

       BroadcastReceiverpermission(在<receiver>标签中应用)限制谁可以发送广播给相应的接收者。该权限会在方法Context.sendBroadcast()返回后才检查,因为在这个时候系统才会尝试将已经提交的广播传递给设定好的接受者。并且,如果没有获取相应的权限结果也不会抛出exception,而是仅仅不将intent传递出去。同样的,可以在方法Context.registerReceiver()中提供权限,用来控制谁可以给programmaticallyregistered receiver(代码编写的注册接受者?)广播。另外还有一个方法是在调用Context.sendBroadcast()方法是提供权限,可以限制哪些BroadcastReceiver对象被允许接受广播。

       ContentProviderpermission(在<provider>标签中应用)限制谁可以访问ContentProvider中的数据。(Content Provider有一个新增的重要的安全措施叫做URIpermission,稍后介绍)与其他的组件不同,该组件有两个单独的权限属性,你可以分别设置:android:readPermission限制谁可以从provider中读取数据,另外一个android:writePermission限制谁可以写入数据。注意如果一个provider同时被读写权限保护的时候,只有写的权限并不意味着你可以从provider中读入数据。当你首次收到provider,对provider进行操作的时候会检查读写权限(如果你读写权限都没有,则会抛出SecurityException)。使用方法ContentResolver.query()要求拥有读的权利,使用ContentResolver.insert(),ContentResolver.update()和ContentResolver.delete()则要求有写的权利。

 

Enforcing Permissions when Sending Broadcasts

       除了给予权限谁可以发送intent给注册的BroadcastReceiver以外,你也可以在发送广播的时候指定权限。通过在调用方法Context.sendBroadcast()时在其中添加权限字符串,接收应用程序必须有你之前定义的权限才可以接收你发送的广播。注意广播接受者和广播发送者都可以要求权限。

 


Other PermissionEnforcement

       Arbitrarilyfine-grained permissions can be enforced at any call into a service. Thisaccomplished with the Context.checkCallingPermission () method.

       用Context.checkCallingPermission()可以在任何调用service的方法中获得权限。用目标权限字符串来调用该方法,它会返回一个明确的整数表示在当前程序中,该权限是否被同意。注意这个方法只有在你执行一个从别的应用程序传递过来的调用的时候才可以使用,通常情况下是从service发出,利用IDL公共接口来传递这个调用。

       还有很多方法来检查权限。如果你有别的线程的pid(线程ID号,process ID),你可以使用Context.checkPermission(String ,int ,int)来检查不利于该线程的权限。如果你有其他应用程序的包名(package name),你可以使用PackageManager方法PackageManager.checkPermission (String, String)检查某个包允许了某个特别的权限。

 

URI Permission

(Web上可用的每种资源,包括HTML文档,图片,视频,程序等,都由一个通用资源标示符,Uniform Resource Identifier进行定位,即称为URI)

       对于Content Provider来说,目前所描述的系统标准权限并不够用。Content Provider可能想通过读写权限来保护自身,但是这样provider的直接用户需要传递特殊的URIs给别的需要操作该provider数据的应用程序。需要权限才可以访问用户的邮件,因为这是用户的敏感私人数据。然而,如果将一个URI图片附件传递给图像浏览器,该图像浏览器没有权限打开这个附件,因为它没有访问所有电子邮件的权限。

       这个问题的解决方法是每个URI都给予权限:当启动一个activity或者返回一个结果给activity的时候,调用者可以设置Intent.FALG_GRANT_READ_URI_PERMISSION and/orIntent.FLAG_GRANT_WRITE_URI_PERMISSION来给予权限。这样给intent中的特殊URI数据访问的权限,忽略该activity是否有权限通过intent访问content provider中的数据。

       这个机制允许最普通的能力-风格模型(capability-style model),这种模型是以用户交互(如打开一个附件,从列表中选择联系人等)为驱动,获取特别的细粒度权限。(This mechanism allows a common capability-stylemodel where user interaction(opening an attachment, selecting a contact fromlist, etc)drives ad-hoc granting of fine-grained permission)。对于减少应用程序需要的权限,这是一个关键措施,这样只给予与该应用程序行为相关的权限。

       URI细粒度权限需要一些content provider的支持,需要这些content provider持有这些URI。强烈建议content provider实现这个实施,content provider可以通过属性android:grantUriPermission或者标签<grant-uri-permission>来声明对这个实施的支持。

       更多的信息可以参照 Context.grantUriPermission(),Context.revokeUriPermission()以及Context.checkUriPermission()方法。

 

 

 

 

 

 

0 0
原创粉丝点击