如何在客户端验证签名并拒绝被篡改资源
解读
面试官抛出此题,并非让候选人背诵“HTTPS 就完事了”。在国内前端工程化场景里,构建产物(JS、CSS、图片、WASM) 经常放在第三方 CDN 或公司自建的 OSS + 边缘节点,一旦回源链路被污染或 CDN 配置被误改,页面就可能加载到被植入挖矿脚本的资源。
Grunt 作为构建阶段的老牌任务运行器,其核心价值在于“在上线前就给出签名,并让浏览器在运行时能校验”。因此,题目真正想考察的是:
- 你能否用 Grunt 插件在构建流水线里生成带签名的资源表;
- 你能否让浏览器在第一时间(资源加载前) 完成校验,拒绝执行/渲染被篡改的文件;
- 你对国内浏览器兼容性、性能损耗、合规性(国密、等保)是否有落地经验。
知识点
- 子资源完整性(SRI)
W3C 标准,通过 integrity 属性把“文件内容 → 哈希 → base64”写死在 HTML 标签里,浏览器下载后异步校验,失败则触发 error 事件并拒绝执行。 - Grunt 插件生态
- grunt-sri:遍历 dist,生成 integrity 清单;
- grunt-cdnify:把本地路径批量改成 CDN 地址并自动插入 integrity;
- grunt-manifest:生成带版本号的 json 清单,供 ServiceWorker 做二次校验。
- 国内 CDN 的特殊性
- 部分云厂商会在回源时自动压缩(gzip/br),导致浏览器算出的哈希与构建时不一致;
- 某些省份运营商会插入广告脚本,SRI 会直接阻断,业务必须第一时间感知并报警。
- 国密 SM3 场景
政务、金融项目要求“SM3 替代 SHA-384”,需要把 grunt-sri 的哈希算法换成 sm-crypto,浏览器端用 wasm 实现 SM3 校验。 - 性能与降级
- 对大型 SPA,integrity 属性会增加 60~80 bytes/文件,首屏可接受;
- 若需兼容 IE11,可降级为动态 script 加载 + 手动哈希校验,失败则 location.reload() 强制回源。
答案
“我会把验证流程拆成构建、发布、运行时三段,全部用 Grunt 自动化。
第一步,构建阶段:
- 用 grunt-contrib-uglify、grunt-contrib-cssmin 压缩后,接着跑 grunt-sri,对 dist 里所有
.js、.css、.wasm计算 SHA-384 并生成sri.json; - 再用 grunt-processhtml 把模板里的占位符
<!--SRI-->批量替换成带 integrity 的 script/link 标签; - 如果客户要求国密,我就把 grunt-sri 的哈希函数换成 sm3,并在浏览器里引入 sm-crypto.min.js,用
postMessage把文件 ArrayBuffer 发到 WebWorker 做异步校验,主线程零阻塞。
第二步,发布阶段:
- 把
sri.json随构建产物一起推到 OSS,设置 HTTP 头Cache-Control: no-transform,防止 CDN 擅自压缩篡改内容; - 在边缘节点配置 ETag = 强哈希,与 integrity 值保持一致,一旦回源被改,ETag 对不上立即 4xx,方便快速定位。
第三步,运行时:
- 对关键入口 JS(如 app.*.js)使用
rel="preload"提前加载,一旦 integrity 校验失败,浏览器会触发window.onerror,我在全局捕获后上报 Sentry,并调用sessionStorage.setItem('__block__',1),后续所有异步 chunk 不再加载,直接跳转到静态降级页; - 对于图片、字体等非执行资源,用 ServiceWorker 拦截 fetch 事件,把 URL 去
sri.json里查哈希,失败则返回 403,避免被运营商插入广告图。
整个方案在 2023 年某省政务云上线,首屏时间增加 < 20 ms,零误拦截,并通过等保三级测评。”
拓展思考
- 双签名机制
如果项目需要离线包 + 在线热更新,可在 Grunt 里再跑一道 RSA 签名,把signature.bin打进 zip 包,客户端先用国密 SM2 验签离线包,再通过 SRI 验在线资源,两层防线互不干扰。 - 动态资源怎么办
对服务端渲染的vendor.dll.js(哈希每次构建会变),可把 integrity 写入 全局 window.SRI,由 SSR 模板直接输出,避免 CDN 缓存旧版本。 - 灰度与回滚
在 Grunt 后置任务里把sri.json上传到配置中心(Nacos/Apollo),灰度发布时只让 5% 节点拉取新哈希,一旦监控发现校验失败率 > 0.1%,立即回滚配置中心版本,实现秒级回退。