本文目录导读:

Subresource Integrity (SRI) 是一种安全机制,它通过加密哈希值来验证浏览器下载的资源(如 JavaScript 或 CSS 文件)是否被篡改,且与服务器预期的内容完全一致。
其核心验证流程可以概括为:浏览器计算下载文件哈希 → 与标签中提供的哈希比对 → 匹配则执行,不匹配则阻止。
下面我们详细拆解这个验证过程,并说明如何实现。
核心验证步骤(浏览器端执行)
SRI 的验证完全由浏览器在后台自动完成,开发者只需要在 <script> 或 <link> 标签中添加 integrity 属性。
假设一个使用了 SRI 的 script 标签如下:
<script src="https://example.com/script.js"
integrity="sha384-MBO5IDfYaE6c6Aao94o+IOGpN+FWri4WzUZV6VGSl3WFAxH2zivVNTrj6WNU+Ug"
crossorigin="anonymous">
</script>
当浏览器请求并下载 script.js 时,验证过程如下:
- 内容抓取:浏览器从 CDN 或服务器下载文件
script.js的内容(原始二进制数据)。 - 哈希计算:浏览器根据
integrity属性中指定的哈希算法(这里是sha384),对下载到的文件内容进行哈希计算,生成一个哈希值。 - 格式解码:
integrity属性中的哈希值使用 Base64 编码,浏览器会对下载到的哈希结果也进行 Base64 编码。 - 值比对:浏览器将自己计算出的哈希值(Base64 编码后)与
integrity属性中的哈希值进行逐字节比对。- 匹配:如果完全一致,说明文件未被篡改,浏览器会继续正常执行脚本或应用样式。
- 不匹配:如果不一致,说明文件内容在传输过程中被修改(可能是 CDN 被黑、中间人攻击等),浏览器会拒绝执行该资源,并且在控制台中抛出一个错误,页面功能可能会因此丢失。
SRI 验证的关键点
多个哈希值与算法
integrity 属性可以包含多个哈希值,用空格分隔,浏览器会选择其中安全级别最高(通常是最新、更长的)的算法进行验证,如果该算法不可用,才会降级尝试下一个。
integrity="sha256-... sha384-... sha512-..."
sha512>sha384>sha256(在 SRI 上下文中,长度越长越安全)
crossorigin 属性的作用
SRI 验证默认不会对跨域资源(不同域名)生效,因为浏览器无法获取该文件的原始字节(会被 CORS 策略阻止)。
关键规则:对于 CDN 等跨域资源,你必须同时设置:
<script>或<link>标签上的crossorigin属性。- 服务器返回的 HTTP 响应头
Access-Control-Allow-Origin。
常见的 crossorigin 值:
anonymous:请求不会携带凭据(如 Cookie),这是最常用的。use-credentials:请求会携带凭据。
如果不设置 crossorigin,浏览器会直接忽略 integrity 属性,导致 SRI 完全失效。 虽然不会报错,但起不到验证作用。
与 CORS 的关系
为了让浏览器能获取文件内容进行哈希计算,资源服务器必须在响应头中返回:
Access-Control-Allow-Origin: * 或 Access-Control-Allow-Origin: https://你的域名.com
否则,当浏览器尝试获取原始内容计算哈希时,会因跨域限制失败,进而阻止资源加载。
如何生成 SRI 哈希值(开发者操作)
你需要使用工具对原始文件内容进行哈希计算,以下是一些常用方法:
方法1:使用 openssl(命令行)
cat script.js | openssl dgst -sha384 -binary | openssl base64 -A
方法2:使用 shasum 和 base64(macOS/Linux)
shasum -a 384 script.js | awk '{print $1}' | xxd -r -p | base64
方法3:使用在线生成器(不推荐用于生产环境,建议本地运行)
搜索 "SRI Hash Generator",有许多安全网站提供此服务。
验证失败会怎样?
- 浏览器行为:
- 对于
<script>:脚本不会被执行,控制台会报错:Failed to find a valid digest in the 'integrity' attribute for resource 'xxx.js' with computed sha384-xxx. The resource has been blocked. - 对于
<link>:样式表不会被应用。
- 对于
- 页面影响:页面可能无法正常运行(JS 缺失)或样式丢失。
- 安全意义:即使攻击者替换了 CDN 上的文件,由于哈希不匹配,浏览器会拒绝执行,保护了用户的安全。
最佳实践总结
- 只对受信任的第三方 CDN 资源使用 SRI(你知道该 CDN 具有 CORS 支持且不会随意更改文件内容),对于自己的域名,你通常已经信任了自己的服务器,SRI 带来的收益较低。
- 务必设置
crossorigin="anonymous"或crossorigin="use-credentials"。 - 确保 CDN 服务器支持 CORS,返回正确的
Access-Control-Allow-Origin头。 - 哈希值应来自你信任的、已知未篡改的原始文件。
- 考虑使用
sha384或sha512,因为它们比sha256更安全,且性能开销在现代浏览器中已可忽略。
一句话总结:SRI 通过让浏览器自己计算下载资源的哈希值,并与开发者预先声明的哈希值比对,从而在文件被执行前就发现篡改,是一种强有力的客户端安全防护手段。