SRI不是“开了就安全”的开关,它仅在脚本URL固定、哈希值正确且浏览器支持时生效;用错会阻断加载致白屏。

直接给结论:SRI 不是「开了就安全」的开关,它只在脚本 URL 固定、哈希值正确、且浏览器支持时才生效;用错地方反而会阻断加载,导致功能白屏。
什么是 SRI 的 integrity 属性,它实际校验什么
SRI 的核心是 integrity 属性,它不是校验域名或证书,而是对远程资源(比如 CDN 上的 lodash.min.js)的响应体做哈希比对。浏览器下载完脚本后,会计算其内容的 SHA-256/384/512 哈希值,再跟 integrity 中的值比对——不一致就拒绝执行,连 onerror 都不会触发。
- 必须搭配
crossorigin属性使用,否则浏览器忽略integrity(即使写了也无效) - 哈希值必须与实际响应体完全一致,包括换行、BOM、压缩与否——本地构建时 minify 工具微小差异都会导致失败
- 只支持
<script>和<link rel="stylesheet">,不适用于fetch()或动态document.createElement('script')
如何生成正确的 integrity 值(别用在线工具凑合)
最可靠的方式是用命令行对目标 URL 的原始响应体做哈希,而不是对本地文件或 HTML 源码。因为 CDN 可能返回不同编码、gzip 后的内容,甚至带重定向。
- 用
curl -sL https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js | openssl dgst -sha384 -binary | openssl base64 -A获取真实响应体的 SHA-384 值 - 避免用
shasum -a 384 lodash.min.js | awk '{print $1}' | xxd -r -p | base64——这校验的是你本地文件,不是 CDN 实际下发的内容 - 如果脚本启用了 Brotli/gzip 压缩,
curl默认可能解压,需加--compressed并确认响应头content-encoding,但通常浏览器校验的是解压后的内容,所以默认curl -sL即可
crossorigin 设成 "anonymous" 还是 "use-credentials"
绝大多数公开 CDN 资源用 crossorigin="anonymous" 就够了。它表示不发送 cookies 或认证头,同时允许浏览器执行 SRI 校验;设成 "use-credentials" 会带上凭据,但要求服务端明确返回 Access-Control-Allow-Origin: *(不能是 * 当前不支持带凭据的通配符),否则跨域请求直接失败。
- CDN 如 jsDelivr、unpkg、cdnjs 都支持
anonymous,响应头含access-control-allow-origin: * - 若你自己的后端托管静态资源,且需要登录态才能访问,则必须用
use-credentials,并确保后端返回access-control-allow-origin: https://your-site.com(不可为*)和access-control-allow-credentials: true - 漏写
crossorigin是 SRI 失效最常见的原因——浏览器控制台不会报错,只是静默忽略integrity
线上出问题怎么快速定位 SRI 失败
SRI 失败时,脚本加载会被中断,控制台出现类似 Failed to find a valid digest in the 'integrity' attribute 的错误,但不会显示具体哪一行——尤其当多个 <script> 都带 integrity 时,得逐个排查。
- 打开 DevTools → Network → 找到对应 JS 请求 → 查看 Preview 或 Response 标签页,确认内容是否和你生成哈希时用的一致(比如有没有多一个空格、末尾换行)
- 临时删掉
integrity和crossorigin,看脚本能否正常加载——排除网络或权限问题 - 用
curl -I检查响应头是否有content-security-policy干预,或strict-transport-security导致 HTTP→HTTPS 重定向改变响应体
真正麻烦的不是生成哈希,而是资源更新后忘记同步 integrity 值,或者 CDN 缓存策略让旧哈希匹配新内容——这类问题往往在灰度发布几小时后才暴露,且无法通过自动化测试覆盖(因为测试环境的 CDN 响应体和生产不一致)。

















