第三方脚本被换掉后页面才会出错,完整性校验能挡到哪一步
第三方脚本被换掉后页面才会出错,完整性校验能挡到哪一步?它能挡「内容和你声明的不一致」这一种:浏览器把取回的文件按指定算法算一次哈希,与你写在标记里的值比对,一致才加载,不一致直接拒绝并报网络错误。它挡不住「这个主机本来就在给你错的东西」。
校验防的是哪一种攻击
文档给出的定位很清楚:完整性校验是一种防御手段,用来确保应用取回的文件内容与你期望的完全一致。典型场景是外部主机被接管后往文件里注入内容——脚本仍然是同一个地址、同一个文件名,字节却变了。
这类攻击之所以有效,是因为多数页面的加载逻辑只看地址,不看内容。浏览器默认信任「从那个地址取回来的东西」,一旦被引用主机失守,问题就直接进入用户会话。校验把信任点从地址扩展到内容,代价是每次升级依赖都要同步更新那串值。
integrity 值怎么写、浏览器怎么比
写法是在引用外部资源的同时给出算法与前缀的 Base64 哈希,浏览器按同一算法计算实际内容,再与列出的值逐个比对;只要有一个匹配就加载,全部不匹配则拒绝加载并报网络错误。
两处细节最容易踩:
- 跨域取资源时必须同时声明 CORS,标记里要带 crossorigin 属性。文档明确说明浏览器不允许 no-cors 的请求使用完整性校验,缺这一项的请求会直接失败,而不是降级为不校验。
- 一份资源可以列多个值。灰度发布时把新旧两版哈希并列,能避免替换瞬间大面积报错,但这只是过渡手段,长期并列会让校验失去意义。
它挡不住的三类情况
第一类是主机本身不可信。校验只保证「拿到的是你指定的那份内容」,指定的内容如果本来就来自一个可以被随意更换对象的地址,攻击者换掉整份文件后同步更新引用值即可绕过。
第二类是同源路径下的替换。校验写在引用标记里,若脚本由站内动态拼接、或由同一台服务器上的其他程序覆盖,则内容变化与值更新可能同时发生。
第三类是合法内容被滥用。签名通过、内容正确,但脚本的执行行为本身超出你的授权范围——比如统计脚本把用户行为送去了不该去的地方,完整性校验完全不涉及这一层。
站内可控的部分是把依赖本地化。第三方脚本改成站内自托管后,引用地址不再受外部主机影响,剩余的校验点变成「谁有权限改这个文件」,这属于权限与备份范畴。内置的 XSS 防护处理的是内容注入,自托管处理的是来源失控,两层不要互相替代。
站内更稳的做法:把依赖本地化
顺序建议这样排:先列清单,把页面里所有非本站域名的脚本、样式与字体列出来;再逐个判断是否必须外部依赖,能本地化的本地化;剩下的保留外部引用但同时加校验与跨域声明;最后把清单纳入发布流程,新增外部依赖时强制说明理由。
清单应当跟着模板走,而不是靠记忆。模板里集中放引用位置,改一处即全站生效,比每个页面单独维护更可靠。
出问题后的恢复顺序
一旦校验失败或脚本被替换,处理顺序影响损失范围。
先断入口:把出问题的引用从模板里摘掉或改指本地副本,让页面先恢复可用。这一步优先级高于定位原因,因为校验失败通常表现为页面局部功能消失,用户侧仍在持续受影响。
再取现场:保留一份失败时的实际文件与响应头,作为后续比对与追责的依据。这一步容易被清缓存的动作覆盖,所以要在清理之前完成。
然后核对可回退的版本与数据:确认最近一次备份覆盖了模板与静态文件,能回到替换前的状态。恢复时按「先程序文件、再数据」的顺序验证,避免把脏文件带回干净数据上。
最后才做加固:把这条依赖改成本地副本、补充校验值、把引用清单写进发布检查项。
常见问题
问:所有脚本都加校验是不是最稳妥? 答:只对确实从外部主机取回的资源有意义。站内资源加了校验不增加防护,反而增加维护成本。
问:加了 crossorigin 会不会让部分用户取不到资源? 答:服务器不返回跨域允许头时,请求会失败。上校验前先用真实网络环境验证引用可用。
问:值多久更新一次? 答:跟随依赖版本更新,而不是按日历更新。定期批量刷新会让校验值和版本脱钩,出错时难以判断哪一份内容对应哪一串值。