You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何阻止第三方应用恶意启动已导出的Activity以避免应用受干扰?

如何阻止第三方应用恶意启动已导出的Activity以避免应用受干扰?

这种情况确实挺闹心的——为了支持Custom Tab的回调跳转,不得不把Activity设为exported="true",结果被别有用心的第三方应用钻空子反复启动,直接搞崩了正常使用。别担心,我给你几个靠谱的解决思路,既能保住Custom Tab的正常功能,又能挡住恶意启动:

  • 第一招:给Intent加“身份验证”,只认合法请求
    你的Activity本来就是用来处理Custom Tab的重定向请求的,这类请求必然带有特定的ACTION_VIEW动作和符合规则的data(也就是你在intent-filter里定义的scheme、host、pathPrefix)。那我们就可以在Activity的启动逻辑里加一道校验:只要不是符合要求的Intent,直接关门送客。

    你可以在MyActivityonCreate方法开头加上这段校验代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent incomingIntent = getIntent();
        // 先检查Intent的动作和数据是否合法
        if (incomingIntent == null 
            || !Intent.ACTION_VIEW.equals(incomingIntent.getAction()) 
            || incomingIntent.getData() == null) {
            finish();
            return;
        }
        // 再精准校验data的scheme、host和路径前缀
        Uri intentData = incomingIntent.getData();
        if (!"myapp".equals(intentData.getScheme()) 
            || !"my.host".equals(intentData.getHost()) 
            || !intentData.getPath().startsWith("/mypage")) {
            finish();
            return;
        }
        // 到这里才是合法请求,继续执行正常业务逻辑
    }
    

    这样一来,第三方用ComponentName直接启动的Intent因为没有ACTION_VIEW和合法的data,一启动就会被直接关闭,根本走不到正常业务逻辑,自然也就干扰不到你的应用了。

  • 第二招:校验调用者身份,只放行可信来源
    除了校验Intent本身,你还可以检查是谁启动了这个Activity。毕竟Custom Tab的重定向请求都是由浏览器类应用发起的,而恶意应用的包名肯定不在你的信任列表里。

    你可以在MyActivity里加一段调用者校验的代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String callerPackage = getCallingPackage();
        // 拿不到调用者信息的直接拒绝
        if (callerPackage == null) {
            finish();
            return;
        }
        // 定义你的信任包名列表:自己的应用包名+常用浏览器包名
        Set<String> trustedPackages = new HashSet<>();
        trustedPackages.add("my.host"); // 你自己的应用包名
        trustedPackages.add("com.android.chrome"); // Chrome浏览器
        trustedPackages.add("com.google.android.webview"); // 系统WebView
        // 可以根据需求添加其他主流浏览器的包名
        
        if (!trustedPackages.contains(callerPackage)) {
            finish();
            return;
        }
        // 剩下的正常业务逻辑
    }
    

    这里要注意,getCallingPackage()在少数特殊场景下可能返回null,所以一定要做判空处理,避免出现意外问题。

  • 第三招:用启动模式缓解干扰(可选,配合前两招效果更好)
    如果你担心极端情况下还是有漏网之鱼,可以给这个Activity设置android:launchMode="singleTask"(在AndroidManifest里)。这样即使第三方多次启动,系统也只会保留一个Activity实例,不会无限创建新页面,能最大程度降低应用崩溃的风险。不过这只是个辅助手段,核心还是前面的身份校验。

    调整后的Activity配置大概是这样:

    <activity android:name="my.host.MyActivity" 
              android:exported="true"
              android:launchMode="singleTask">
        <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:host="my.host" 
                  android:pathPrefix="/mypage" 
                  android:scheme="myapp" />
        </intent-filter>
    </activity>
    

一般来说,把第一招和第二招结合起来用,就能形成双重保险,既不影响Custom Tab的正常跳转,又能把恶意启动彻底挡在门外。

内容来源于stack exchange

火山引擎 最新活动