12、WebView安全:JavaScript接口、文件域访问、XSS攻击
WebView,说白了就是App里内嵌的一个浏览器。很多App用它来展示网页内容、加载H5页面,甚至直接做核心业务界面。但便利的背后,往往藏着大坑。
我这些年做安全测试,WebView出问题的案例太多了。有的App直接把核心业务逻辑写在H5里,有的给JavaScript开了太多权限,还有的文件域访问完全没限制。嗯,今天我们就来把这些坑一个个填上。
12.1 JavaScript接口:最危险的“后门”
WebView允许Java和JavaScript互相调用,这个机制叫JS Bridge。Android提供了addJavascriptInterface方法,能把Java对象暴露给JS。
听起来很方便对吧?但方便和安全往往是矛盾的。
addJavascriptInterface暴露的对象方法,JS都可以直接调用。这意味着如果暴露了一个能执行系统命令的方法,攻击者就能远程控制你的App。
我曾经在一个金融类App里发现,开发人员把整个数据库操作类都暴露给了JS。攻击者只需要构造一个恶意页面,就能读取用户的所有交易记录。嗯,这个漏洞评级直接给了Critical。
安全配置建议
- 最小权限原则:只暴露必要的方法,不要整个对象丢出去
- 使用@JavascriptInterface注解:Android 4.2+必须加这个注解,JS才能调用
- 版本判断:API 17以下,建议直接禁用JS接口
- 输入校验:所有从JS传入的参数,都要做严格的类型和范围检查
// 安全示例:只暴露必要方法
public class JSBridge {
private Context mContext;
public JSBridge(Context context) {
this.mContext = context;
}
@JavascriptInterface
public String getUserName() {
// 只返回用户名,不返回敏感信息
return "user_" + getUserId();
}
@JavascriptInterface
public void shareContent(String title, String url) {
// 对参数做校验
if (title == null || title.length() > 100) return;
if (url == null || !url.startsWith("https://")) return;
// 执行分享逻辑
}
// 危险!不要暴露这个方法
// @JavascriptInterface
// public void executeCommand(String cmd) { ... }
}
12.2 文件域访问:不该打开的“门”
WebView默认可以访问本地文件系统。通过file://协议,JS能读取App私有目录下的文件。你想想看,如果攻击者诱导用户加载了一个恶意页面,这个页面就能读取/data/data/包名/shared_prefs/下的所有配置信息。
我记得有个电商App,把用户的登录Token存在了SharedPreferences里。WebView又开启了文件域访问,结果一个XSS漏洞就让攻击者拿到了所有用户的Token。嗯,这个教训很深刻。
文件域访问控制
| 配置项 | 说明 | 推荐值 |
|---|---|---|
setAllowFileAccess(true) |
允许WebView加载file://协议 | false(除非必要) |
setAllowFileAccessFromFileURLs(true) |
允许file://页面中的JS访问其他文件 | false |
setAllowUniversalAccessFromFileURLs(true) |
允许file://页面中的JS访问任意来源 | false |
12.3 XSS攻击:WebView里的“隐形杀手”
XSS(跨站脚本攻击)在WebView里同样致命。攻击者通过注入恶意JS代码,可以窃取Cookie、劫持会话、甚至调用JS Bridge暴露的接口。
为什么会这样?因为WebView本质上就是一个浏览器,所有Web安全漏洞在这里都会复现。而且由于JS Bridge的存在,XSS在WebView里的危害往往比普通浏览器更大。
常见XSS攻击场景
- 反射型XSS:通过URL参数注入恶意脚本
- 存储型XSS:恶意脚本存储在服务器,每次加载都执行
- DOM型XSS:通过修改DOM结构触发恶意代码
// 危险示例:直接拼接HTML
String userInput = getIntent().getStringExtra("content");
webView.loadDataWithBaseURL(null,
"<html><body>" + userInput + "</body></html>",
"text/html", "UTF-8", null);
// 如果userInput包含<script>alert('xss')</script>,就会执行
// 安全做法:对输入做HTML转义
String safeInput = TextUtils.htmlEncode(userInput);
webView.loadDataWithBaseURL(null,
"<html><body>" + safeInput + "</body></html>",
"text/html", "UTF-8", null);
12.4 知识体系总览
下面这张图,是我整理WebView安全测试时常用的知识框架。你可以把它当作检查清单来用。
12.5 实战检查清单
每次做WebView安全测试,我都会按这个清单过一遍。你也试试看。
- 是否使用了
addJavascriptInterface?暴露了哪些方法? - 是否在API 17以下使用了JS接口?
- 文件域访问是否关闭?
- 是否加载了不可信的第三方URL?
- 是否对用户输入做了HTML转义?
- 尝试构造恶意JS代码,测试JS Bridge接口
- 使用
file:///data/data/包名/路径尝试读取本地文件 - 在输入框、URL参数中注入
<script>alert(1)</script> - 检查WebView的
WebChromeClient和WebViewClient实现
WebView安全,说白了就是三个字:管住门。管住JS接口的门,管住文件访问的门,管住输入输出的门。门管好了,攻击者就进不来。
公众号:蓝海资料掘金营,微信deep3321