Android:验证意图发送者的身份



我在一家生产多个应用程序的公司工作,并不是所有的应用程序都有相同的签名或更类似的签名,我们目前至少有5-6个应用程序证书。

我们试图创建一种机制,让同一设备上的所有公司应用程序共享相同的is,例如,如果用户从市场安装了应用程序A,但没有安装应用程序,则会生成一个新的ID,如果现在他安装了应用程序A,则应用程序B应该具有与应用程序A相同的ID (ID只是生成的UUID类型#4)等等…

我们目前正在使用broadcast,只有经过我们许可的应用程序才能接收到该广播,并将id发送回另一个广播(这次是显式的)。广播和响应由我们的签名级别许可保护,这当然没有帮助,因为我们有多个签名。

我试图写一个意图广播和恢复,可以有它自己的保护机制,不限于只有一个签名,但几个,问题是像Binder.getSenderUID()这样的东西不适合广播,我得到我自己的uid。看起来我没有办法得到我男朋友的身份,除非他自己在意图中写下他的id,这是我不能相信的,因为它很容易被伪造。使用加密需要应用程序自带密钥,这是不安全的,转向服务器进行验证需要太多时间,并且不能保证成功,因为不能100%确定周围有网络。

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

和往常一样,我从来没有得到一个合适的答案,如果有的话!的答案,所以我不得不自己去找。

Intents的问题是不可能获得发送者,因为它们在网络中并行于多播,其中发送者的地址不重要。

如果我想获得服务器的UID,我需要做一个"远程"进程,即使他是本地的,而不是使用广播IPC,我需要使用AIDL与IBInder实现。一旦我有了一个Binder对象,我可以调用我的服务getCallingUid()并获得调用者的uid,这将允许我要求PackageManager给我它的公共证书(不要求进程本身,我要求操作系统),并将其与我在apk中提前准备的一组证书进行比较。

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

希望这能帮助到别人

抱歉回复晚了…

Bind需要时间,更重要的是,它是异步的。然而,有一种方法可以进行同步绑定——当然,假设您尝试联系的服务当时已经启动。Android允许更多的BroadcastReceiver(本质上是异步的,因此不能使用正常的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);

注意,你没有绑定到服务,所以一定要偷看每次使用

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

按如下方式声明Activity,使其像BroadcastReceiver一样"静音":

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

灵感:如何获得Intent的发送者?

我正在寻找一种方法来验证发送意图的应用程序的包名。在我的应用中,处理intent-filter的activity要求intent sender在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
         }
    }
}

跑龙套类

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 "";
    }

最新更新