如何在Android中使用自定义权限?

63

我有两个应用程序。

其中一个声明权限并只有单个Activity

AndroidManifest.xml 的一部分

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:permission="your.namespace.permission.TEST" >
    <activity
        android:name=".DeclaringPermissionActivity"
        android:label="@string/app_name" >

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <intent-filter> 
         <action android:name="android.intent.action.VIEW" /> 
         <category android:name="android.intent.category.DEFAULT" /> 
         <category android:name="android.intent.category.BROWSABLE" /> 
         <data android:scheme="myapp"
             android:host="myapp.mycompany.com" /> 
        </intent-filter> 
    </activity>
</application>
第二个声明使用权限
AndroidManifest.xml的一部分
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="your.namespace.permission.TEST" />

<application

Activity的一部分:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("myapp://myapp.mycompany.com/index")));
}

我正在安装应用程序并声明权限,然后运行第二个应用程序。

结果我遇到了安全性异常:

 01-11 09:46:55.249: E/AndroidRuntime(347): java.lang.RuntimeException: Unable to start activity ComponentInfo{your.namespace2/your.namespace2.UsingPErmissionActivity}: java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.VIEW dat=myapp://myapp.mycompany.com/index cmp=your.namespace/.DeclaringPermissionActivity } from ProcessRecord{407842c0 347:your.namespace2/10082} (pid=347, uid=10082) requires your.namespace.permission.TEST

我只想指出这个漏洞:http://commonsware.com/blog/2014/02/12/vulnerabilities-custom-permissions.html - Tobrun
关于上面提到的漏洞评论,请注意 Android 5.0 中解决此问题的更改:http://developer.android.com/about/versions/android-5.0-changes.html#custom_permissions - Nonos
https://developer.android.com/guide/topics/permissions/defining - k4dima
5个回答

108

我创建了一个测试代码,你可以使用它来检测你的权限。有两个应用程序PermissionTestClient,它声明了权限并通过此权限保护其活动。这是它的清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.testpackage.permissiontestclient"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />
    <permission android:name="com.testpackage.mypermission" android:label="my_permission" android:protectionLevel="dangerous"></permission>

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:permission="com.testpackage.mypermission"
            android:name=".PermissionTestClientActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter >
                <action android:name="com.testpackage.permissiontestclient.MyAction" />
                <category android:name="android.intent.category.DEFAULT" />                
            </intent-filter>
        </activity>
    </application>

</manifest>

Activity文件中没有什么特别的,因此我在这里不会展示它。

PermissionTestServer应用程序从PermissionTestClient调用Activity。以下是其清单文件:

<?xml version="1.0" encoding="utf-8"?>

<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="com.testpackage.mypermission"/>

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <activity
        android:name=".PermissionTestServerActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>

活动(Activity):

package com.testpackage.permissiontestserver;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class PermissionTestServerActivity extends Activity {
    private static final String TAG = "PermissionTestServerActivity";

    /** Called when the activity is first created. */
    Button btnTest;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btnTest = (Button) findViewById(R.id.btnTest);
        btnTest.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.d(TAG, "Button pressed!");
                Intent in = new Intent();
                in.setAction("com.testpackage.permissiontestclient.MyAction");
                in.addCategory("android.intent.category.DEFAULT");
                startActivity(in);
            }
        });
    }
}

要进行测试,只需从服务器应用程序中删除uses-permission。您将获得安全违规错误。


2
谢谢,我的错误是只将permission属性放在了<application>元素中。 - pixel
1
当我在PermissionTestClient中使用android:protectionLevel="signature"时,这对我不起作用。我在该应用程序的启动器上使用权限并获得以下结果:Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=my.package.foobar/.DashboardActivity } from null (pid=4070, uid=2000) requires my.custom.permission.ACCESS_ACTIVITY - 因此,该应用程序无法启动自己的Activity 0_o。 - fr1550n
4
权限签名级别意味着您的客户端和服务器应该使用相同的证书进行签名。尝试使用危险级别启动代码,如果一切正常,则尝试使用签名启动。还有一件事,如果您使用签名,我认为您需要导出已签名的APK文件,然后安装它们。 - Yury
我想向大家通报一个与使用自定义权限相关的安全漏洞。请参阅此commonsware帖子:http://commonsware.com/blog/2014/02/12/vulnerabilities-custom-permissions.html - Tobrun
1
在定义自定义权限时,请不要忘记添加“android:description =“string resource””属性,这将有助于在Marshmallow中显式请求权限。 - VIN
这会弹出一个对话框,提示用户在应用程序B中接受权限吗?如果是的话,如何避免这种情况,签名级别权限? - Mike6679

35

你需要在基础应用程序的清单中声明它,以独占方式创建权限。例如:

<permission android:name="your.namespace.permission.TEST"
    android:protectionLevel="normal" android:label="This is my custom  permission" />

然后在您想要的应用程序中使用它:

<uses-permission android:name="your.namespace.permission.TEST" />

注意:安装应用程序时,以自定义权限的方式维护安装顺序非常重要。例如,您必须首先安装声明该权限的应用程序,然后再安装使用该权限的应用程序。如果顺序混乱,可能会破坏自定义权限的使用。


简洁而有效。最高票答案更好,但这正是问题所要求的。需要注意的是,这是您使用自定义权限所需的全部内容,因为安全管理器会处理其余部分。 - Igor Čordaš
3
只要我记得没错,安装应用程序的顺序也很重要。首先安装声明自定义权限的应用程序,然后安装使用该自定义权限的应用程序。 - waqaslam
1
我们可以在创建权限的应用程序内使用自定义权限吗? - Bharath Booshan
将自定义权限放入两个应用程序中,您就不必担心哪个应用程序先安装。 - Sanchit
1
这个还有效吗?我无法复现安装顺序的 bug。我只在一个应用程序中放置了权限定义 (<permission />)。无论我以哪种顺序安装应用程序(我每次测试运行都卸载了两个),它总是可以工作-至少对于“签名”受保护的权限... - ToBe
显示剩余3条评论

7
正如答案中所提到的,您还应考虑安装应用程序的顺序。
这很重要,因为:
如果在定义权限的应用程序(App A)之前安装请求权限的应用程序(App B),则特定设备中将没有此定义的权限,因此操作系统不会要求授予权限。
稍后,当您安装 App A 并尝试运行 App B 时,后者将无法访问安全组件。
其中一个解决方法是在应用程序 A 和 B 中定义相同的自定义权限,以确保权限存在于设备中,无论首先安装哪个应用程序,因此当安装应用程序 A 时,权限已授予应用程序 B。
但在这种情况下,您应确保两个声明中的保护级别相同,因为这可能会导致安全风险。
(请注意,在 Android 5.0 及更高版本中,除非使用相同的签名密钥对这些应用程序进行签名,否则无法在多个应用程序中定义相同的权限。)

有没有针对Android 5.0及以上版本的不同签名密钥的解决方案? - vicky

3

接受的答案展示了创建自定义权限所需的正确流程。我有一些笔记,可以在测试后决定要使用哪个权限和权限名称。

android:protectionLevel="normal" // don't need user confirmation to grant, similar to some low-risk permission like android.permission.INTERNET

android:protectionLevel="dangerous" // need user confirmation to grant // similar to some high-risk permission like android.permission.CAMERA

android:protectionLevel="signature" // both app need to sign with the same signature

在 Android < 6 版本中,用户在安装或更新应用程序时授予dangerous权限。Android 会自动处理此过程,我们无需编写代码。

在 Android >= 6 版本中,用户使用应用程序时需要授予 dangerous权限(运行时权限)。我们需要编写代码来请求运行时权限。

在 Android 10,Pixel 4XL上测试,Android 危险权限名称需要分为两部分,labeldescriptionicon不是必需的,但不影响权限的工作。

<permission
        android:name="my.MyCustomPermission" // work well
        android:name="MyCustomPermission" // not work, the runtime permission dialog won't show
        android:label="" // don't required
        android:description="" // don't required
        android:icon="" // don't required

1

定义自定义权限是使用<Permission>标签完成的。 请点击下面的链接,在应用程序中使用用户定义的权限:

声明和执行权限


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接