12、WebView安全:JavaScript接口、文件域访问、XSS攻击

WebView,说白了就是App里内嵌的一个浏览器。很多App用它来展示网页内容、加载H5页面,甚至直接做核心业务界面。但便利的背后,往往藏着大坑。

我这些年做安全测试,WebView出问题的案例太多了。有的App直接把核心业务逻辑写在H5里,有的给JavaScript开了太多权限,还有的文件域访问完全没限制。嗯,今天我们就来把这些坑一个个填上。

12.1 JavaScript接口:最危险的“后门”

WebView允许Java和JavaScript互相调用,这个机制叫JS Bridge。Android提供了addJavascriptInterface方法,能把Java对象暴露给JS。

听起来很方便对吧?但方便和安全往往是矛盾的。

⚠️ 高危警告: 在Android 4.2(API 17)以下,任何通过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
💡 我的习惯: 除非App的核心功能必须加载本地HTML文件,否则我建议直接关闭所有文件域访问。如果确实需要,也要把HTML文件放在assets目录下,而不是可写的外部存储。

12.3 XSS攻击:WebView里的“隐形杀手”

XSS(跨站脚本攻击)在WebView里同样致命。攻击者通过注入恶意JS代码,可以窃取Cookie、劫持会话、甚至调用JS Bridge暴露的接口。

为什么会这样?因为WebView本质上就是一个浏览器,所有Web安全漏洞在这里都会复现。而且由于JS Bridge的存在,XSS在WebView里的危害往往比普通浏览器更大。

常见XSS攻击场景

  1. 反射型XSS:通过URL参数注入恶意脚本
  2. 存储型XSS:恶意脚本存储在服务器,每次加载都执行
  3. 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安全测试时常用的知识框架。你可以把它当作检查清单来用。

WebView安全知识体系 JavaScript接口 @JavascriptInterface注解 最小权限原则 API版本兼容处理 文件域访问 setAllowFileAccess(false) 禁止file://协议访问 assets目录存放HTML XSS攻击防护 HTML转义处理 Content-Security-Policy 输入输出双重校验 核心原则:最小权限 + 严格校验 + 及时更新

12.5 实战检查清单

每次做WebView安全测试,我都会按这个清单过一遍。你也试试看。

📋 自动化扫描检查项:
  • 是否使用了addJavascriptInterface?暴露了哪些方法?
  • 是否在API 17以下使用了JS接口?
  • 文件域访问是否关闭?
  • 是否加载了不可信的第三方URL?
  • 是否对用户输入做了HTML转义?
🔍 手动渗透测试项:
  • 尝试构造恶意JS代码,测试JS Bridge接口
  • 使用file:///data/data/包名/路径尝试读取本地文件
  • 在输入框、URL参数中注入<script>alert(1)</script>
  • 检查WebView的WebChromeClientWebViewClient实现
🔧 避坑指南: 我曾经遇到一个App,开发人员说“我们WebView只加载自己的服务器页面,不会有XSS”。结果我发现在某个页面里,用户昵称没有做转义就直接显示出来了。攻击者只需要注册一个带恶意脚本的昵称,就能攻击所有查看该用户资料的人。所以记住:永远不要信任任何输入,哪怕它来自你自己的服务器。

WebView安全,说白了就是三个字:管住门。管住JS接口的门,管住文件访问的门,管住输入输出的门。门管好了,攻击者就进不来。


公众号:蓝海资料掘金营,微信deep3321