深入掌握Chrome DevTools Security面板实战技巧
先看效果,再看代码
说实话,我之前一直没怎么正经用过浏览器的 Security 面板。平时调试基本靠 Network 看接口、Console 打日志、Elements 改 DOM。直到上周线上一个 HTTPS 混合内容警告把我坑惨了——用户打不开上传组件,排查半天才发现是某个 script 被自动降级成 HTTP 加载了。
那次之后我决定把 Security 面板彻底摸一遍。结果发现这玩意儿其实贼实用,尤其是上线前做一次完整安全检查,能提前避掉一堆坑。
直接上最常用的场景:检测页面是否完全走 HTTPS。打开 DevTools → Security 标签页,刷新页面,你会看到类似这样的信息:
Security
Overview: Connection secure
Certificate: Valid
Resources loaded via HTTPS: 100%
Mixed content: None detected
但如果页面里有 HTTP 资源,就会变成这样:
Mixed content: Yes (1 blocked, 2 warnings)
http://jztheme.com/static/js/legacy.js — blocked
http://jztheme.com/assets/img/icon.png — insecure image
注意那个 blocked 和 warning 的区别:脚本类资源(JS/CSS)如果走 HTTP,会被现代浏览器直接拦截;图片、iframe 这种可能只是黄标提示,但依然存在风险。
这个场景最好用
我最近在做一个老系统迁移项目,原站用了大量内网地址和自定义证书。开发阶段根本没法保证 HTTPS,但又要让前端跑起来。这时候 Security 面板就成了我的“信任开关”指南。
比如访问一个带自签名证书的测试环境:https://test.jztheme.com:8081,页面会白屏,提示 NET::ERR_CERT_INVALID。常规操作是点高级→继续前往,但这对自动化测试或 CI 环境不现实。
解决方案分两步:
- 在 Chrome 地址栏输入
thisisunsafe(没错,就是连协议都不用输),页面会自动刷新并临时信任该证书 - 回到 Security 面板,点击右上角的“View certificate”,导出证书用于后续配置
虽然这不是长期方案,但在本地联调时亲测有效。别问我怎么知道的,折腾了整整一下午才从同事那偷学到这一招。
核心代码就这几行
当然,真正想根治问题还得改代码。最常见的混合内容问题来自动态拼接 URL。比如这段烂代码我就写过:
function loadScript(module) {
const isProd = location.hostname === 'jztheme.com';
const baseUrl = isProd ? 'https://' : 'http://';
const script = document.createElement('script');
script.src = ${baseUrl}jztheme.com/plugins/${module}.js;
document.head.appendChild(script);
}
看起来逻辑没问题,但一旦页面被代理到 HTTPS(比如 Nginx 反向代理),而判断条件又只看 hostname,就会导致实际运行在 HTTPS 下却加载了 HTTP 资源——完美触发混合内容拦截。
改进方式很简单:用协议相对路径或者直接省略协议。
// 方式一:双斜杠开头(推荐)
script.src = '//jztheme.com/plugins/${module}.js';
// 方式二:直接用 HTTPS(更安全)
script.src = 'https://jztheme.com/plugins/${module}.js';
别小看这个改动,上线后 Security 面板里的“Mixed content”直接从 5 条降到 0。
高级技巧:强制 HTTPS + HSTS 检查
如果你的服务已经全面启用 HTTPS,建议加上 HSTS 响应头。这能让浏览器强制使用加密连接,哪怕用户手动输 HTTP 也会被重定向。
Nginx 配置示例:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
配置完后,在 Security 面板能看到明确提示:
HSTS: Enabled (max-age=31536000)
HSTS includes subdomains: Yes
这里注意下我踩过坑的地方:HSTS 的 max-age 一旦设置,浏览器会在有效期内记住这个规则,即使你后面把 header 删了也没用。所以开发阶段千万别在本地启 HSTS,否则清理缓存都救不了你,只能等时间过期或者手动去 chrome://net-internals/#hsts 清除。
调试 WebSocket 安全问题
很多人不知道 Security 面板还能看 ws/wss 的安全状态。我们有个实时通信模块用了 WebSocket,之前一直用 ws:// 测试,上线切 wss 后发现连接失败。
通过 Security 面板发现原因是证书域名不匹配:后端用的是 *.api.jztheme.com 泛域名证书,但我们连接的是 ws://realtime.jztheme.com,不在 SAN 列表里。
修复方法有两个:
- 更新证书,把 realtime.jztheme.com 加进 SAN
- 前端改用 wss://gateway.jztheme.com 并走反向代理
最终选了第二种,因为成本低且可控。改完后在面板里能看到:
Connection: Secure (TLS 1.3)
Protocol: WSS
Certificate: Valid
多说一句,WebSocket 的错误通常不会出现在 Console,必须主动去看 Security 和 Network 面板才能定位。
踩坑提醒:这三点一定注意
以下是我在实战中总结的三个最容易翻车的点,每一条都是拿线上事故换来的教训。
第一,iframe 嵌套第三方页面时的安全警告
我们有个管理后台要嵌入外部报表系统,用 iframe 包了一下。结果 Security 面板报了一堆“insecure passive content”。原因是对方站点虽然是 HTTPS,但某些静态资源用了 HTTP。解决不了对方的问题,我们只能加个中间页做代理转发,自己补全 SSL。
第二,Service Worker 缓存了 HTTP 资源
PWA 项目里,SW 一旦缓存了非安全资源,后续即使主站升级 HTTPS,这些资源还是会从缓存加载,导致 Security 面板持续报警。建议在 SW 安装阶段就做协议校验:
self.addEventListener('install', event => {
event.waitUntil(
caches.open('v1').then(cache => {
return fetch('/manifest.json')
.then(res => res.json())
.then(manifest => {
const validResources = manifest.assets.filter(asset =>
asset.url.startsWith('https://') || asset.url.startsWith('/')
);
return cache.addAll(validResources);
});
})
);
});
第三,开发服务器热更新走的是 HTTP
很多本地开发服务器(webpack-dev-server/vite)默认用 HTTP 提供 HMR 功能。当你在 HTTPS 页面引入本地脚本时,就会触发混合内容拦截。解决方案是给 dev server 配 HTTPS:
// vite.config.js
export default {
server: {
https: true,
host: 'localhost'
}
}
启动后访问 https://localhost:3000 就不会再被 Security 面板红标警告了。
这个技巧的拓展用法还有很多,后续会继续分享这类博客
以上是我个人踩坑后的总结,希望对你有帮助。Security 面板看似冷门,其实关键时刻能救命。特别是上线前跑一遍检查,比用户反馈后再修要体面得多。
顺带提一句,Chrome 最近还加了个“Safety Check”功能(设置里能找到),可以批量扫描书签、密码、扩展的安全性,配合 Security 面板一起用,算是前端+用户侧双重保障了。
这个技巧的拓展用法还有很多,比如结合 CSP 报告分析、预检证书过期时间等等,后续会继续分享这类实战型博客。有更优的实现方式欢迎评论区交流。

暂无评论