WebView安全实现(一)_webview实现-CSDN博客
上一篇说到WebView的介绍以及对应的攻击面,这里用一张图来总结一下webview的攻击面;
图来源大佬演讲的PPTbbs.kanxue.com/article-14155.htm
WebView攻击面
通过上图可以看到,WebView的攻击路径/入口一般是
- Intent
- deeplink
- 特殊端口、协议
而攻击点则有且不仅限于这些常见的问题函数
- loadUrl()
- loadDataWithBaseURL()
- evaluateJavascript()
- loadData()
- 等
WebView不安全配置项
- setAllowFileAccess(true)
- setAllowFileAccessFromFileURLs(true)
- setAllowUniversalAccessFromFileURLs(true)
- 等
具体的漏洞以及利用方式可以查看上一篇文章介绍WebView安全实现(一)_webview实现-CSDN博客
其本质是APP提供了对外接受参数,或者说外部输入,然后对这些输入内容没有进行限制;在了解到这些问题的根源后,很多时候安全工程师就根据这些情况提供了对应修复方案,但是安全工程师是不了解其中的具体业务,所以提供的安全修复建议基本上就是禁用这几个风险函数,常见的一句话修复方案这里列举一些;
- 禁用JavaScript,配置setJavaScriptEnabled(false);
- 使用loadUrl(),使用白名单方案;
也不是说这些修复方案有问题,或者说是错误的,但是这样子提供给到研发去修复问题非常容易造成修复不完整二次漏洞出现,或者说禁用不了这个问题;下面讲一下一些场景;
一句话修复方案突破
1. 沙盒突破
- 漏洞原理:JS 通过未受控的 API 桥接访问原生资源,导致子应用突破限制访问到超级应用中;
- 典型案例:
- 任意文件读取:启用
setAllowFileAccess(true)
时,攻击者读取file:///data/local/tmp/
等目录。 - API 滥用:调用
addDownloadTask()
下载恶意资源
- 任意文件读取:启用
2. 白名单绕过
校验方式 | 绕过手法 |
---|---|
url.contains() |
attacker.com?baidu.com (参数污染) |
url.endsWith() |
baidu.com.attacker.com (子域名欺骗) |
正则表达式错误 | javascript://baidu.com%0aalert(1) |
身份混淆攻击:
// 错误解析:将用户名误判为域名
String url = "https://safe.com@malicious.com";
// 实际访问 malicious.com,但被识别为 safe.com
3. 特权API漏洞利用
超级应用提供给子应用的API,超级应用在接受调用的时候没有验证子应用的调用权限,导致权限滥用;或者是验证机制可被绕过,如:
- **超级应用未验证子应用调用权限:**子应用调用高权API;
- **能力令牌泄露:**子应用后端未校验请求源 → 恶意域名获取令牌 → 调用高权 API;
这部分会涉及到具体的业务,需要安全研究员对具体的业务比较了解,才能够进行限制绕过;
防御方案与最佳实践
1. 基础配置加固
webView.getSettings().setAllowFileAccess(false); // 禁用 File 协议
webView.getSettings().setAllowContentAccess(false);
webView.getSettings().setJavaScriptEnabled(false); // 非必要不启用 JS
如果业务需要用到相关JS能力,就禁用不了JS,那就需要如下的考虑;
a) 在加载不受信任的内容时删除 JavaScript 接口
确保在 WebView 加载不受信任的内容之前,通过调用 removeJavascriptInterface 移除来自 JavaScript 接口的对象。例如,这可以通过调用 shouldInterceptRequest
请求。
b) 仅通过 HTTPS 加载 Web 内容
有一些业务场景在用不了白名单的情况,需要加载不受信任的内容,那么请确保 WebView 通过加密连接加载网页内容。通过在 AndroidManifest
文件中将 android:usesCleartextTraffic
设置为 false
,或在网络安全配置中禁止 HTTP 流量,防止在未加密的连接上执行初始页面加载。
要确保未加密的流量不会发生重定向和进一步的应用浏览,请检查 loadUrl
或 shouldInterceptRequest
的请求;
c) 验证不受信任的内容
如果在 WebView 中加载了任何外部链接,请同时验证 scheme 和 host(允许列表域)。任何不在允许列表中的域都应该由默认浏览器打开。(白名单机制)
d) 不加载不受信任的内容
如果可以,请仅将应用开发者拥有的严格限定范围的 URL 和内容加载到 WebView 中。(白名单机制)
e) 不要暴露敏感数据
如果应用程序使用 WebView 访问敏感数据,请考虑使用 clearCache
方法删除本地存储的所有文件,然后再使用 JavaScript 接口。还可以使用服务器端标头(如 no-store)来指示应用程序不应缓存特定内容。
f) 不要公开敏感功能
如果应用程序需要敏感权限或收集敏感数据,请确保从应用程序内的代码中调用它,并向用户提供醒目的披露信息。避免将 JavaScript 接口用于任何敏感作或用户数据。
到这里也算是解答了我在第一篇中提出的这个问题;
若是业务上需要把URI的配置交给用户(如一些toB的业务上),那这种情况要如何处理?
2. 白名单校验升级
前面提到了很多业务需要加载外部域名,但是存在各种情况,绝大部分都是建议是用白名单机制,遇到不受信的域名通过外部打开,那具体的白名单检测规则如果没有提供给到研发,就会出现一千个哈姆雷特的情况,前面也已经介绍了各种绕过方式;
- 严格域名匹配:
// 使用正则全字匹配
private boolean isValidDomain(String url) {
return Pattern.matches("^https://(www\\.)?baidu\\.com/.*", url);
}
- 动态令牌绑定:能力令牌需关联 AppID + 时间戳 + 数字签名。
3. 运行时防护
- 子帧(iframe)隔离:禁止第三方域 iframe 调用原生 API;
- WebView 事件同步:使用 Draco 等框架解决时序竞争漏洞。
- **云端接口API验证:**API接口调用,需要验证除超级应用用户身份外,也需加上子应用调用权限验证或者其他业务参数验证;
- **端API验证:**所有超级应用提供的API都应该验证子应用的调用权限;
4. 场景
越讲到后面就越概念了,因为这部分要根据具体的场景来判断具体的修复或者说处理方案,我这里列几个场景;
- WebView加载的URL做成了用户可配置项;
- 子应用可访问API做成了收费模式;
- 等
这种业务场景就需要进行安全评估,定制具体的安全方案了;
5. 组合
这里就是通过其他漏洞结合WebView这块的问题进行利用,不是单单看WebView的修复就能解决;
比如Intent + WebView 组合漏洞、DeepLink + WebView 组合漏洞;
当然这些还是比较片面,只是个人在实际方案中遇到的部分场景,所罗列和描述比较简单,如果说的有问题的或者有补充的欢迎大佬们提出。