Android 安全性和权限

自定义权限 permissionandroid

<permission
android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="normal"
android:label="@string/permlab_install_shortcut"
android:description="@string/permdesc_install_shortcut" />shell

声明的含义以下;浏览器

android:label:权限名字,显示给用户的,值但是一个 string 数据,例如这里的“自定义权限”。安全

android:description:比 label 更长的对权限的描述。值是经过 resource 文件中获取的,不能直接写 string 值,例如这里的”@string/test”。app

android:name:权限名字,若是其余 app 引用该权限须要填写这个名字。ide

android:protectionLevel:权限级别,分为 4 个级别:this

○normal:低风险权限,在安装的时候,系统会自动授予权限给 application。orm

○dangerous:高风险权限,系统不会自动授予权限给 app,在用到的时候,会给用户提示。xml

○signature:签名权限,在其余 app 引用声明的权限的时候,须要保证两个 app 的签名一致。这样系统就会自动授予权限给第三方 app,而不提示给用户。对象

○signatureOrSystem:这个权限是引用该权限的 app 须要有和系统一样的签名才能授予的权限,通常不推荐使用。

 

声明和强制实施权限

要强制执行本身的权限,首先必须使用一个或多个<permission>标签,在AndroidManifest.xml文件中来声明它们。

例如,应用程序想要控制谁可以启动它的一个Activity,就可以用下面的方法来为这个操做声明一个权限:

<manifestxmlns:android="http://schemas.android.com/apk/res/android"
    package="com.me.app.myapp">
    <permissionandroid: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>属性是可选的,而且只用于帮助系统把相关权限显示给用户。一般用标准的系统组来设置这个属性,固然也可使用本身定义的组(但这不多见)。咱们推荐使用既存的分组,这样会简化给用户的显示的权限UI。

要注意的时,权限所支持的label和description属性。它们是可以显示给用户的字符串资源,android:label属性用于权限列表的显示,android:description属性用于单一权限的详细介绍。label属性值应该是简短的,用几个关键的单词来描述被权限保护的功能。description属性应该是权限的详细描述,惯例是使用两句话,第一句话来描述权限的功能,第二句话用来警告用户,若是应用程序得到了这个权限会带来的不利影响。

下面是一个申请CALL_PHONE权限的label和description属性设置的例子:

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

用系统的Settings应用程序和shell命令:adb shell pm list permissions,可以查看系统中当前定义的权限。Settings应用的使用方法是:Settings->Applications,选择一个应用程序,向下滚动,能够看到这个应用程序所使用的权限。对于开发者,带有“-s”选项的adb命令能够用与用户查看格式相相似的格式来显示权限:

$ adb shell pm list permissions -s
AllPermissions:

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>标签)限制了谁可以启动被关联的Activity。在Context.startActivity()方法和Activity.startActivityForResult()方法执行期间要检查这个权限,若是调用者没有要求的权限,那么就会从调用中抛出一个SecurityException异常。

Service的权限(应用于<service>标签)限制了谁可以启动或绑定被关联的服务。在Context.startService()方法、Context.stopService()方法和Context.bindService()方法执行期间会检查这个权限,若是调用者没有要求的权限,那么就会从调用中抛出一个SecurityException异常。

BroadcastReceiver的权限(应用于<receiver>标签)限制了谁可以发送广播通知给关联的接收器。在Context.sendBroadcast()方法返回后会检查这个权限,也就是在系统试图把提交的广播通知发送给设定的接收器的时候。在因没有权限而失败的时候,它不会向调用者抛出一个异常,它只是不发送Intent对象。一样,给Context.registerReceiver()方法提供的权限,是用来控制谁可以向程序中注册的接收器发送广播。另外一种方式是,在调用Context.sendBroadcast()方法时,提供一个权限,来限制那个BroadcastReceiver对象可以接收广播通知。

ContentProvider的权限(应用于<provider>标签)限制了谁可以访问ContentProvider对象中的数据。(内容提供有一套额外的叫作URI权限的重要且易用的安全权限,稍后会介绍。)跟其余组件不一样,它有两个独立的权限属性:android:readPermission用于限制谁可以从提供器中读取数据;android:writePermission用于限制谁可以向提供器中写入数据。要注意的是,若是提供器受到读写权限的保护,只拥有写权限并不意味着可以从提供器中读取数据。在首次获取提供器和执行提供器相关的操做时,会进行权限的检查(若是没有权限,就会抛出一个SecurityException异常)。使用ContentResolver.query()方法查询数据时,要求具备读权限,使用ContentResolver.insert()方法、ContentResolver.update()方法、ContentResolver.delete()方法编辑数据时,要求具备写权限。在全部的场景中,若是没有要求的权限,这个调用就会致使一个SecurityException异常被抛出。

发送广播时的强制权限

除了强制谁可以把Intent对象发送给一个BroadcastReceiver对象的权限以外,在发送一个广播通知时,还能够指定需求权限。经过调用带有权限字符串的Context.sendBroadcast()方法,能够要求接收器必需要拥有这个权限,才可以接受这个广播通知。

要注意的是,接收器和广播器都可以要求权限,发生这种状况时,双方的权限都必须检查经过后,才能够把Intent对象发送给匹配的目标。

其余强制性权限

在调用Service过程当中,能够设置更细粒度的权限。这种设置是经过调用Context.checkCallingPermission()方法来完成的。调用时给这个方法传入所指望的权限字符串,它会返回一个整数,它指明了所指望的权限是否被当前调用的进程所接受。要注意的是,这种方法只能在执行来自另外一个进程调用的时候使用。一般经过IDL接口来发布服务,或者是用其余的方法提供给另外一个进程。

有不少有用的检查权限的方法。若是有另外一个进程的PID,那么就可使用Context.checkPermission(String, int, int)方法,针对这个PID来检查权限。若是有另外一个应用程序的包名,就能够直接使用包管理器的PackageManager.checkPermission(String, String)方法来找出这个包是否已经被授予了指定的权限。

URI权限

到目前为止咱们所介绍的标准的权限系统不能知足内容提供器的使用须要。内容提供器可能要保护它本身的读写权限,可是为了某些操做,它的客户端也须要把指定的URI交给另外一个应用程序来处理。一个典型的示例是Mail应用程序中的附件。邮件的访问应该是受到权限的保护,由于这个用户敏感的数据。可是,若是要把一个图片附件的URI提供给一个Image浏览器,那么这个Image浏览器就会因没有权限而不能打开这个图片附件。

这个问题的解决方案是给每一个URI都分配一个权限,当启动一个Activity或给一个Activity返回结果时,调用者可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION和(或)Intent.FLAG_GRANT_WRITE_URI_PERMISSION权限。这样就给接受Intent对象的Activity授予了访问Intent对象中指定的数据URI的权限,而无论它是否有权访问与这个Intent对象对应的内容提供器中的数据权限。

这种机制容许使用一种共同的能力样式模型,这种模型利用用户交互(打开一个附件、选择一个通信录等)来驱动设定更细粒度的权限。这种机制能够有效的减小应用程序所须要的权限,只须要那些与它们直接相关行为权限。

这种把权限细化到URI的作法,须要持有这些URI的内容提供器的配合。强烈推荐内容提供器实现这种机制,而且经过android:grantUriPermissions属性或<grant-uri-permissiongs>标签来声明它们所提供的权限。

更多的信息可以在Context.grantUriPermission()、Context.revokeUriPermission()和Context.checkUriPermission()方法中找到。

相关文章
相关标签/搜索