面试题十八:如何跨App启动Activity?有哪些注意事项?

如何跨App启动Activity?有哪些注意事项?

一、面试官视角:这道题想考察什么?

  • 是否了解如何启动外部应用的Activity
  • 是否了解如何防止自己的Activity被外部非正当启动
  • 是否对拒绝服务漏洞有了解
  • 如何在开发时规避拒绝服务漏洞

二、题目剖析

1、如何启动外部应用的Activity

  • 共享uid的App
1
2
3
4
5
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.apkok.android"
android:sharedUserId="com.apkok"
...
</manifest>
1
2
3
// kotlin中使用

startActivity(Intent().setComponent(ComponentName("com.apkok.app.b","com.apkok.app.b.BActivity")))
  • 使用exported
1
2
3
AndroidManifest.xml清单文件中:
// 当exported为true的时候,这种方式是将该Activity暴露在了系统当中,随便哪个应用都可以直接访问该Activity。
<activity android:name=".BActivity" android:exported="true"/>
1
2
3
// kotlin中使用

startActivity(Intent().setComponent(ComponentName("com.apkok.app.b","com.apkok.app.b.BActivity")))
  • 使用intentFilter(隐式启动)
1
2
3
4
5
6
<activity android:name=".BActivity">
<intent-filter>
<action android:name="com.apkok.intent.TEST"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
1
2
3
// kotlin中使用

startActivity(Intent("com.apkok.intent.TEST"));

2、为允许外部启动的Activity加权限

1
2
3
4
5
6
7
8
9
10
11
App B中的Activity B:

<permission android:name="com.apkok.b"/>

<activity android:name=".BActivity"
android:permission="com.apkok.b">
<intent-filter>
<action android:name="com.apkok.intent.TEST"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
1
2
3
4
5
6
App A中的Activity A:

<uses-permission android:name="com.apkok.b"/>

// kotlin中使用
startActivity(Intent("com.apkok.intent.TEST"));

注意:如果通过权限的方式在App A中的Activity A来启动App B中的Activity B,需要确保App B要比App A先安装,这样的话,在App A中才可以获取到权限,反之亦然。

3、拒绝服务漏洞

场景:App A中的Activity A要启动App B中的Activity B,这样的话,Activity A就是攻击者,Activity B是受害者,在Activity B把自己暴露出来了之后,会出现什么情况呢?

假设Activity A启动Activity B的时候,传递参数的时候,往Bundle里面扔了一个SerializableA,但SerializableA这个类只在App A里面有,App B里面没有,但我们都知道Bundle在收到数据之后,只要你在Activity B里面去访问了Intent的Extras,它就一定会把里面的数据进行反序列化出来,那么在反序列化的过程当中,如果有一个它不知道的类,那就会抛出一个找不到类的异常,这就是我们通常所说的拒绝服务漏洞。

1
2
3
4
5
// kotlin代码

class SerializableA: Serializable

startActivity(Intent("com.apkok.intent.TEST.B").putExtra("SerializableA", SerializableA()))
1
2
3
4
5
6
// WXEntryActivity.java

private void handleIntent(Intent intent) {
SendAuth.Resp resp = new SendAuth.Resp(intent.getExtras());
...
}

以上代码场景是:App A中的Activity A启动微信App进行微信登录授权或使用微信的一些服务的时候,微信会要求我们集成WXEntryActivity类,这个类里面有个handleIntent()方法,方法里面会调用intent.getExtras()方法,这个时候就会将我们传递过来的SerializableA进行反序列化,但在反序列化的过程中,因为微信App里没有SerializableA类,那么就会抛出一个找不到类的异常。

这种问题如何解决呢?

  • Activity中读取Intent的Extras的时候,使用try、catch捕获异常
1
2
3
4
5
6
7
8
9
10
修改WXEntryActivity.java代码:

private void handleIntent(Intent intent) {
try {
SendAuth.Resp resp = new SendAuth.Resp(intent.getExtras());
...
}catch(Exception e) {
e.printStackTrace();
}
}

题目结论

  • 跨App启动Activity首先要明确App之间的关系

    比如是否sharedUserId

  • 外部可启动exported或有intentFilter的Activity

    exported不推荐使用

  • 可外部启动的Activity,需要注意拒绝服务漏洞

  • 尽量不暴露Activity,为暴露的Activity加权限控制

  • Intent的Extras读取时要注意捕获异常