WebView 的默认配置并不适合承载不可信内容,尤其是当应用需要加载远程网页时,一些看似无害的设置可能会被恶意页面利用。攻击者可以通过构造特殊 URL 或调用暴露的 Java 对象来执行任意代码、窃取本地数据,甚至在用户无感知的情况下发起敏感操作。因此,理解每一项配置背后的攻击面,是做好 WebView 安全加固的第一步。

一、JavaScript 开关与 Java 接口暴露的风险
WebView 中 setJavaScriptEnabled(true) 是很多功能实现的前提,例如调用网页中的脚本逻辑、执行前端框架的渲染任务。但一旦启用 JavaScript,页面中的代码就可以尝试访问 WebView 暴露的 Java 对象。Android 4.2 之前,addJavascriptInterface 允许 JavaScript 通过反射调用任意 Java 方法,这几乎等同于把应用的控制权交给了远程页面。Android 4.2 之后虽然要求方法上标注 @JavascriptInterface,但仍然不能掉以轻心,因为任何被标注的公开方法都可能被恶意脚本调用。
更安全的做法是默认不启用 JavaScript,只在确实需要加载受信任页面时才打开。如果业务必须暴露 Java 方法给网页使用,应当把接口对象的方法数量降到最低,并且严格校验调用来源。例如,只允许来自自家 https 域名的页面调用接口,同时避免在接口方法中传递敏感数据或执行危险操作。下面是一个相对安全的初始化示例:
WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); settings.setAllowFileAccess(false); settings.setAllowFileAccessFromFileURLs(false); settings.setAllowUniversalAccessFromFileURLs(false); settings.setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW); // 仅在需要时添加接口,并确保方法最小化 webView.addJavascriptInterface(new SafeBridge(), "AndroidBridge");
如果应用不需要 JavaScript 交互,就直接禁用它。很多漏洞的根源就是开发者为图方便保留了 JavaScript 开关,却没有意识到后续加载的内容可能已经不受自己控制。接口暴露方面还有一个常见错误:把整个 Activity 或 Context 对象通过 addJavascriptInterface 传给网页,这会让页面拿到远超预期的能力。应当新建独立类,只暴露明确指定的方法,并且在方法内部再次校验 URL 来源。
二、URL 跳转校验与白名单机制
shouldOverrideUrlLoading 是拦截网页跳转的主要入口,但仅仅判断 URL 是否以某个前缀开头远远不够。攻击者可以利用 https://trusted.com@evil.com 这种形式,或者利用重定向、大小写混用、URL 编码等方式绕过简单的前缀匹配。比如 https://trusted.com.evil.com 与 https://trusted.com 在字符串前缀判断中可能产生误判。
正确的做法是解析 URL 的 scheme 和 host,只允许 http 或 https 协议,并且 host 必须严格等于白名单域名,不能使用 contains 或 startsWith 进行模糊判断。如果业务需要支持多个子域名,可以单独维护子域名列表,而不是用通配符盲目放开。下面是一个完整的拦截示例:
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
String scheme = uri.getScheme();
String host = uri.getHost();
if (scheme == null || host == null) {
return true;
}
boolean schemeOk = "http".equals(scheme) || "https".equals(scheme);
boolean hostOk = "trusted.ipipp.com".equals(host);
if (!schemeOk || !hostOk) {
// 拒绝不被信任的跳转
return true;
}
// 还可以进一步校验路径,避免开放整站跳转
return super.shouldOverrideUrlLoading(view, request);
}
});
除了页面跳转,还需要关注 shouldInterceptRequest,因为它可以拦截资源请求。如果在这里没有做安全过滤,恶意页面可能加载任意资源。另一个容易忽视的点是 setSupportMultipleWindows 和 setJavaScriptCanOpenWindowsAutomatically,它们可能允许网页打开新窗口,从而绕过当前 WebView 的拦截逻辑,需要对 onCreateWindow 进行同样严格的校验。
三、SSL 证书校验与混合内容防护
很多开发者在实现 onReceivedSslError 时直接调用 handler.proceed() 来忽略证书错误,这种做法会让应用暴露在中间人攻击之下。攻击者可以伪造证书拦截通信,窃取用户登录态或注入恶意脚本。安全的处理方式应该是在证书错误时终止加载,或者将错误信息上报并展示给用户确认,同时确保确认过程本身不能被网页自动触发。
对于必须访问受信任自签名证书的场景,不要全局信任所有证书,而是将特定证书或公钥固定(pinning)在应用内。可以通过 HttpsURLConnection 或自定义 TrustManager 实现,但需注意 Android 7.0 以后官方推荐使用网络安全配置。下面的代码展示了如何在 WebView 客户端中拒绝所有 SSL 错误:
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// 不要直接 handler.proceed();
handler.cancel();
// 可以在此记录错误或提示用户
}
});
混合内容是指 HTTPS 页面中加载 HTTP 资源。Android 5.0 之前 WebView 默认允许混合内容,这会让加密页面被明文资源拖垮。可以使用 setMixedContentMode 进行控制:MIXED_CONTENT_NEVER_ALLOW 完全禁止,MIXED_CONTENT_COMPATIBILITY_MODE 仅对部分被动内容放宽。建议优先使用 NEVER_ALLOW,如果业务确实需要兼容旧资源,应尽量推动迁移到 HTTPS,而不是依赖兼容模式。同时关闭 setAllowFileAccess、setAllowFileAccessFromFileURLs 和 setAllowUniversalAccessFromFileURLs,防止远程页面读取本地文件。
四、WebChromeClient 与敏感资源管理
WebChromeClient 负责处理 JavaScript 对话框、文件选择、权限请求等交互。默认实现可能放行危险操作,例如网页调用 alert()、confirm() 时,如果自定义对话框没有正确实现,可能导致 UI 欺骗。更关键的是 onShowFileChooser,它允许网页触发文件选择器。如果不加限制,恶意页面可能诱导用户选择敏感文件并读取内容。
在 onShowFileChooser 中应当校验发起请求的 URL 是否可信,并且限制可选择的文件类型。另外,如果应用不需要处理文件上传,直接返回 false 禁止即可。对于 onPermissionRequest 也要谨慎处理,例如网页请求摄像头或麦克风权限时,不要无条件同意,而应提示用户并在回调中明确授权范围。下面是一个禁用文件选择并最小化权限请求的示例:
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
// 如果不支持文件上传,直接拒绝
return false;
}
@Override
public void onPermissionRequest(PermissionRequest request) {
// 只允许受信任来源的权限请求,且需经过用户确认
request.deny();
}
});
移除不需要的接口也是敏感资源管理的关键。如果之前添加过 addJavascriptInterface,在页面销毁或不再需要时,可以通过 removeJavascriptInterface 移除。同时,当 WebView 不再使用时,应该在 Activity 或 Fragment 的 onDestroy 中调用 webView.destroy(),避免内存泄漏和后台线程继续运行带来的安全风险。对于加载过的历史记录和缓存,也可以根据业务需要调用 clearCache 或 clearHistory 降低敏感数据残留。
综合来看,WebView 安全配置不是单一开关的问题,而是一整套访问控制策略的落地。从 JavaScript 和接口暴露的最小化,到 URL 白名单的严格解析,再到 SSL 错误与混合内容的强制阻断,每一步都在缩小攻击面。开发者在接入 WebView 时,不妨把这些配置项当作默认模板,再根据具体业务逐步开放,而不是先放开所有功能再考虑收敛。
WebView安全Android WebView混合应用安全修改时间:2026-09-19 18:43:08