在 WebView 里,页面的安全传输完全取决于宿主 App 的配置,而默认值充满敌意。Android 从 Pie 起默认拦截混合内容,却不提供证书锁定,onReceivedSslError 默认静默取消加载;无数 App 用 handler.proceed() 信任任何证书来「修」白屏,结果被 Google Play 拒审、还给中间人攻击开了后门。iOS WKWebView 依赖 ATS,却没有干净的按请求证书锁定接口。宿主自有 runtime 提供统一传输策略:强制 HTTPS、锁定证书、失败即阻断,并给出可解释的真实错误,而不是死屏。
Android:混合内容被拦,但证书是你的难题
自 Android 9(Pie,API 28)起,WebView 默认拦截混合内容——HTTPS 页面不能再通过明文 HTTP 拉取脚本、图片或 iframe。在此之前默认是放行的。要放宽规则需调用 setMixedContentMode,但任何更宽松的模式(COMPATIBILITY 或 ALWAYS_ALLOW)都会削弱保障,生产环境明确不推荐。
更大的陷阱在证书。当 WebView 遇到不受信任、过期或域名不符的证书时,WebViewClient.onReceivedSslError 触发,默认动作是取消加载——也就是静默白屏。开发者从 Stack Overflow 抄来的「标准解法」是 handler.proceed(),它会接受任何证书、关闭全部校验。Google Play 会主动拒绝这类忽略 SSL 错误的 App,也让网络攻击者轻易实施中间人攻击。WebView 同样不内置证书锁定:锁定已知公钥需要手工搭建网络层,几乎没人做。
iOS:ATS 拦明文,但证书路径粗糙
WKWebView 受益于 App Transport Security——默认拦截明文 HTTP,仅通过显式 Info.plist 例外放行。但证书处理很粗糙:证书错误以通用的鉴权挑战(带 server-trust 保护空间的 didReceiveAuthenticationChallenge)出现,没有按请求锁定接口,也没有内置「告诉用户出了什么问题」的流程。开发者常用的捷径是无条件接受 server trust——测试机可以,生产环境既可能被拒审又是安全漏洞。更早的 iOS 版本连 WKWebView 的 SSL 错误钩子都没有,证书出错直接失败。
没有统一传输策略会失去什么
- 混合内容静默失败。 被默认拦截的脚本和图片让页面残缺,却没有可见原因。
- 盲目信任证书。
proceed()/ 无条件信任让任意 Wi-Fi 都可能成为拦截点。 - 没有锁定。 被攻破或误签的 CA 可为你的域名签发「合法」证书,WebView 照单全收。
- 静默失败。 默认证书错误路径是白屏,而非用户或 App 可处理的错误。
- 不一致。 Android 与 iOS 在默认值、接口、失败模式上各异,同一页面跨平台表现不同。
runtime 解法
宿主自有 runtime 在页面之下提供统一传输策略:强制 HTTPS 与 HSTS,锁定服务器公钥使恶意 CA 无法冒充,对任何证书校验错误失败即阻断,并以可解释的真实错误替代白屏(含清晰标注的安全兜底开关)。页面在每个平台都获得单一、可预期的安全传输契约,宿主也能证明连接确实受保护。
| 维度 | WebView | 宿主自有 runtime |
|---|---|---|
| 混合内容 | Pie 起默认拦截,放宽即削弱 | 强制,无静默降级 |
| 证书错误默认 | 静默取消 / 白屏 | 失败即阻断,错误可解释 |
| 证书锁定 | 无内置,需手搓 | 按源强制锁定 |
| iOS 证书路径 | 粗糙的 server-trust 挑战 | 统一策略,同一接口面 |
| 中间人暴露 | 用了 proceed 即高危 | 锁定 + 严格校验封死 |
| 跨平台 | 默认与接口各异 | 处处同一契约 |
浏览器以「安全路径为默认、不安全路径可见」赢得信任;原生 WebView 却把不安全路径做成诱人捷径、把失败路径做成白屏。runtime 恢复这一契约:强制 HTTPS、锁定证书、解释错误,绝无用户从未同意的静默降级。
参考来源
- Android Developers — WebSettings.setMixedContentMode:API 28 起默认拦截混合内容,宽松模式不推荐 — 静默混合内容默认值。
- Android Developers — WebViewClient.onReceivedSslError:默认取消加载;Google Play 拒绝 proceed() — 白屏陷阱及其危险「解法」。
- Apple Developer — App Transport Security:明文 HTTP 默认拦截 — iOS 基线。
- Apple Developer — WKNavigationDelegate didReceive:server-trust 挑战,无按请求锁定 — 粗糙的 iOS 证书路径。
- web.dev — Web on Android:WebView 将安全敏感行为委托给宿主 App — 为何传输安全在 App 侧而非 Web 侧。