给外部脚本加完整性校验,为什么标签里还要显式写跨域属性
给外部脚本加完整性校验时,标签里还要显式写跨域属性,原因是校验依赖跨域请求这一前提。文档写明:由于请求带完整性校验的资源必须使用跨域请求,因此必须在标记里包含跨域属性。没有它时,浏览器对这类资源的取用方式与校验要求不一致,校验值就无从判定,结果往往是资源被直接拒绝加载,或者校验形同虚设。
校验发生在哪一步
它发生在资源下载之后、执行之前:浏览器算出内容的摘要,与标签里给的值比对,不匹配就不使用这份资源。它保护的是「引用没被换掉」这一段,也就是内容分发节点或外部脚本源被替换的场景,不保护脚本本身做了什么。被换掉的脚本往往正是跨站脚本(XSS)的入口,这条校验降低的是「加载到被动过手脚的文件」的概率,文件加载之后做了什么仍要靠来源限制来管。
所以它适合挂在版本固定的第三方脚本与样式上。会随内容变化的引用不适合加,因为每次源文件更新都会导致校验失败,页面直接缺样式或缺交互。
为什么必须显式写跨域属性
跨域属性决定了请求以什么模式发出。默认情况下,脚本与样式的取用不带完整的跨域语义,浏览器拿到的响应无法安全地参与摘要比对。显式声明后,请求按跨域模式发出,校验才有可比的输入。
最常见的事故是只加了校验值忘写跨域属性:本地测试时因为缓存命中看不出来,正式上线后才出现资源加载失败。反过来只写跨域属性不加校验,则完全没有校验效果。两类要成对出现。
| 写法要点 | 常见错误 | 出现时的表现 |
|---|---|---|
| 校验值与跨域属性成对 | 只给校验值 | 资源被拒绝加载,页面缺样式或无交互 |
| 多算法备选 | 只给单一摘要 | 源文件换算法后整站同时失败 |
| 版本固定引用 | 对动态内容加校验 | 每次更新都触发失败 |
| 批量替换后复核 | 只改脚本不改样式 | 一半引用仍走旧摘要 |
校验值的格式与备选
值是一份或多份内容摘要,以空白分隔。每份摘要由算法前缀、一个短横和编码后的哈希值组成,允许的前缀有 sha256、sha384 和 sha512 三种。同时给多个摘要的价值在于过渡:源文件在下一次更新时只要匹配其中任意一份就能正常加载,站点不需要在同一个发布窗口里同步换掉所有引用。
生成摘要时要以实际下发的文件为准,不要用压缩合并前的源文件;中间经过构建步骤的话,要在构建产物上取哈希,否则线上内容与计算基准不一致。
模板侧的批量核对
引用点通常散落在模板的公共头尾里,改一次要同时动脚本与样式。站内有全站替换工具,适合批量修这类引用点,但批量改完必须复核:替换是按文本匹配的,跨模板的写法差异(属性顺序、是否带其他参数)容易漏掉一部分。
更稳的顺序是先在测试站上跑一遍全站引用清单,把加了校验的资源逐个请求一次,确认摘要与产物一致,再上生产。模板改动如果同时借助站内的可视化模板编辑能力完成,改完仍要按同一份清单核对,编辑能力不会替你验证线上摘要。
常见问题
加了校验之后 CDN 换证书会不会失败? 不会,校验只比对文件内容摘要,与传输层证书无关;但 CDN 若对文件做了压缩改写,就会失败。
内部脚本要不要加? 同域且随构建变化的资源不必加,价值集中在固定版本的外部引用上。
校验失败会不会有提示? 浏览器控制台会记录,普通访客只看到功能缺失,因此灰度期要主动比对引用清单。
能长期只给单一算法吗? 可以,但换算法时要一次改完所有引用;给两份摘要能把过渡期拉开。