android:验证意图发件人的身份

时间:2013-03-20 07:37:12

标签: android android-intent broadcastreceiver secure-coding

我在一家生产多个应用程序的公司工作,并非所有这些应用程序具有相同的签名,或者更像是我们暂时拥有至少5-6个应用程序证书。

我们尝试创建一种机制,其中同一设备上的所有公司应用程序共享相同的内容, 例如,如果用户从市场App A安装并且未安装应用程序,则将生成新ID,如果现在他安装应用程序A,则应用程序B应具有与应用程序A相同的ID(id仅是生成的UUID类型#4)等...

我们目前正在使用广播,只有获得我们许可的应用才能接收该广播,并通过另一次广播发送回来(这次是明确的)。 广播和回复都受到我们的签名级别的保护,这当然没有帮助,因为我们有多个签名。

我尝试编写一个意图广播和恢复,它可以拥有自己的保护机制,不仅限于一个签名而是几个,问题是像Binder.getSenderUID()这样的东西不能用于广播和我得到了自己的uid。 看起来我无法获得我的snder的身份,除非他自己在意图中写了他的id,这不是我可以信任的东西,因为它可以很容易伪造。 使用加密需要应用程序附带一个密钥,而不是再次受到保护,转向服务器进行验证需要花费太多时间,并且在移动设备上无法保证成功,因为不是100%确定有网络。

任何人都知道如何从一个应用程序获得另一个应用程序的验证\安全消息?(我的所有应用程序但可能有不同的签名)。

4 个答案:

答案 0 :(得分:5)

在这里,如果有任何挑战性问题,我永远不会得到合适的答案!回答,所以我不得不自己找到它。

Intents的问题在于,无法获取发件人,因为他们与发送者地址不重要的网络中的mulicast并行。

如果我希望获得snder的UID,我需要进行“远程”处理,即使他是本地的,而不是使用广播IPC,我需要使用AIDL和IBInder实现。 一旦我有一个Binder对象,我可以在我的服务中调用getCallingUid()并获取调用者的uid,这将允许我让PackageManager给我它的公共证书(不询问过程本身,我问操作系统)并比较它是我在apk中提前准备的一组证书。

另一方的调用应用程序(发送给我ID的另一个进程)只需要使用bindService(service,conn,flags)方法绑定到我。 这种方法的缺点是当然是耗时的过程,Bind需要时间,它是通过内核的异步调用,并不像绑定到本地服务那么快。此外,因为我可能有几个应用程序,我需要同步访问我的内部ID,所以只有第一个没有失败的绑定调用将为我设置和ID。 我仍然需要检查是否可以使用阻止多线程问题的Messanger方法。

希望这有助于其他人。

答案 1 :(得分:2)

很抱歉迟到的回复...

绑定需要时间,更重要的是,它需要异步。 但是,有一种方法可以进行同步绑定 - 当然,假设您尝试联系的服务当时已经开始。 Android为BroadcastReceivers提供了更多功能(它本质上是异步的,因此无法使用普通的bindService),BroadcastReceiver有一个" peekService"方法

如果您想在不收听广播的情况下使用它,您可以这样做:

final IBinder[] b = new IBinder[1];
new BroadcastReceiver() { 
    public void onReceive(Context context, Intent intent) {
        b[0] = peekService(context, intent);
    }
}.onReceiver(context, intent);

IMyInterface i = IMyInterface.Stub.asInterface(b[0);

请注意,您没有绑定到该服务,因此请务必查看每次使用。

答案 2 :(得分:0)

如前所述,绑定可能是解决此问题的最佳方法。但是,您可以考虑切换到Activity而不是BroadcastReceiver,然后您可以使用getCallingActivity(),假设您使用startActivityForResult()启动。

按照以下方式声明您的活动以使其成为"沉默"像BroadcastReceiver:

<activity
    android:name=".FauxReceiver"
    android:theme="@android:style/Theme.NoDisplay" 
    android:excludeFromRecents="true"
    android:noHistory="true"
>
    <intent-filter>
        ...
    </intent-filter>
</activity>

灵感:How to get the sender of an Intent?

答案 3 :(得分:-1)

我一直在寻找一种方法来验证发送我的intent-filter收到的意图的应用程序的包名称。我的应用程序中处理intent-filter的活动要求intent发送者在Intent Extras字段中包含其进程ID。然后,我的接收活动可以从ActivityManager获取关联的应用程序包名称。

以下是我在通过StackOverflow进行转换时找到的一些示例代码。

两个应用所需的常量

public static final String EXTRA_APP_ID;
public static final String ACTION_VERIFY = "com.example.receivingapp.action.VERIFY";

致电活动

    Intent verifyIntent = new Intent();
    verifyIntent.setAction(Consts.ACTION_VERIFY);
    verifyIntent.putExtra(EXTRA_APP_ID, android.os.Process.myPid());
    // Verify that the intent will resolve to an activity
    if (verifyIntent.resolveActivity(getPackageManager()) != null) {
    startActivityForResult(verifyIntent, Consts.REQUEST_VERIFY);
    } else {
       Log.d(TAG, "Application not found.");
    }

接收应用

清单

        <activity
            android:name="com.example.receivingapp.ReceivingActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="com.example.receivingapp.VERIFY" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

ReceivingActivity

if (getIntent().hasExtra(OnyxCoreConsts.EXTRA_APP_ID)) {
    string appName = null;  
    // Resolve intent
    if (getIntent().getAction().equals(ACTION_VERIFY) {    
         int appPid = getIntent().getIntExtra(EXTRA_APP_ID, -1);
         if (-1 != mAppPid) {
             appName = Utils.getAppNameByPID(mContext, mAppPid);
         }
         if (null != appName && !"".equalsIgnoreCase(appName)) {
              // Do something with the application package name
         }
    }
}

Utils class

public static String getAppNameByPID(Context context, int pid){
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

        for (RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
            if (processInfo.pid == pid) {
                return processInfo.processName;
            }
        }
        return "";
    }