本文目录导读:

- 目录导读
- 什么是SRI子资源完整性?核心概念与为什么你需要它
- SRI的工作原理:如何通过哈希值“锁死”外部资源
- SRI vs. CSP内容安全策略:两者如何互补
- SRI的浏览器支持现状
- SRI实战:从生成哈希到部署全流程
- SRI的局限性与避坑指南
- SRI常见问答
- 为什么SRI是现代Web安全必修课
SRI子资源完整性:从原理到实战,全面守护网页加载安全
目录导读
- 什么是SRI子资源完整性? – 核心概念与为什么你需要它
- SRI的工作原理 – 如何通过哈希值“锁死”外部资源
- SRI vs. CSP内容安全策略 – 两者如何互补
- SRI的浏览器支持现状 – 哪些浏览器已完美支持
- SRI实战:从生成哈希到部署全流程 – 含代码示例
- SRI的局限性与避坑指南 – CDN失效、动态脚本等难题
- SRI常见问答 – 开发者最关心的10个问题
- 为什么SRI是现代Web安全必修课
什么是SRI子资源完整性?核心概念与为什么你需要它
SRI(Subresource Integrity,子资源完整性) 是一种安全机制,允许浏览器在加载外部资源(如JavaScript、CSS文件)时,验证该资源是否被篡改,它就像给每个外部文件盖上了“数字指纹”——如果CDN上的文件被人恶意插入恶意代码,浏览器会拒绝执行。
为什么需要SRI?
根据Google Web安全报告,超过30%的网站使用了外部CDN资源,而CDN本身就是“单点故障”的高危环节,攻击者一旦攻破CDN服务器,或实施“供应链攻击”,就能通过修改jQuery、Bootstrap等库,向数百万网站投毒,SRI正是阻断这条攻击链的“最后一道门锁”。
实例
假设你的网站使用了https://cdn.example.com/jquery.min.js,攻击者将该文件替换成包含挖矿脚本的版本,如果没有SRI,浏览器会“信任”地执行它;而添加了SRI标签后,浏览器计算实际文件的SHA256哈希值,与你配置的“预期哈希值”比对,不一致则拒绝加载。
SRI的工作原理:如何通过哈希值“锁死”外部资源
核心流程
- 生成哈希:开发者使用工具(如
openssl)对原始资源文件计算哈希值(支持SHA256、SHA384、SHA512)。 - 嵌入标签:将哈希值作为
integrity属性写入<script>或<link>- 浏览器验证:浏览器下载资源后,计算其哈希值,并与
integrity值对比,若一致则执行,否则报错并阻止加载。 - 浏览器验证:浏览器下载资源后,计算其哈希值,并与
关键属性
integrity="{hash-algorithm}-{base64-hash}":例如sha256-abc123...。crossorigin:必须设置为anonymous或use-credentials(CDN资源通常需要此属性,因为跨域请求默认不携带凭据)。
示例代码
<script src="https://cdn.example.com/boostrap.min.js"
integrity="sha384-... (实际哈希)"
crossorigin="anonymous"></script>
SRI vs. CSP内容安全策略:两者如何互补
很多开发者误以为CSP(Content Security Policy,内容安全策略)可以替代SRI,但两者解决的是不同层面问题:
| 特性 | SRI | CSP |
|---|---|---|
| 核心作用 | 验证资源完整性(防止篡改) | 控制资源来源(防止恶意域名) |
| 防护目标 | 已信任源但文件被篡改 | 未授权源的恶意资源加载 |
| 执行方式 | 客户端计算哈希比对 | 服务端通过HTTP头部声明白名单 |
| 适用场景 | 固定版本库的CDN资源 | 动态资源的来源限制 |
最佳实践:
同时使用两者,CSP限制“哪些域名可以被加载”,SRI验证“加载来的文件是否是真的”。
Content-Security-Policy: script-src 'self' https://cdn.example.com 'strict-dynamic'
再配合integrity属性,实现双重保险。
SRI的浏览器支持现状
自2015年起,主流浏览器已全面支持SRI:
- Chrome:45+版本(2015年)
- Firefox:43+版本
- Safari:11+版本(但macOS 10.11+需注意WebKit bug)
- Edge:17+版本(Chromium内核)
- Opera:32+版本
需要注意:
- IE11:不支持SRI(但可配合
<meta http-equiv="Content-Security-Policy">做降级处理)。 - 部分旧版移动浏览器:如Android 4.4的WebView,不支持。
- 非权威CDN:如果CDN没有正确返回
Access-Control-Allow-Origin头部,导致跨域请求失败,SRI验证也会失败。
SRI实战:从生成哈希到部署全流程
步骤1:计算哈希值(三种最常用方法)
使用OpenSSL
curl -s https://cdn.example.com/lib.js | openssl dgst -sha384 -binary | openssl base64 -A
使用Node.js
const crypto = require('crypto');
const fs = require('fs');
const fileBuffer = fs.readFileSync('./lib.js');
const hash = crypto.createHash('sha384').update(fileBuffer).digest('base64');
console.log(`sha384-${hash}`);
使用在线工具(如report-uri.com的SRI生成器)——但注意,敏感资源请勿使用第三方在线工具。
步骤2:写入HTML标签
<script src="https://cdn.example.com/vue@3.2.0/vue.global.prod.js"
integrity="sha384-4Q...(实际哈希)"
crossorigin="anonymous"></script>
步骤3:验证
打开浏览器开发者工具→控制台:若资源被篡改,会看到Failed to find a valid digest in the 'integrity' attribute for resource错误。
步骤4:自动化(适用于构建流程)
- Webpack:使用
webpack-subresource-integrity插件 - Gulp:使用
gulp-sri插件 - Nginx反向代理:可在nginx层面附加
integrity属性(需结合SSI)
SRI的局限性与避坑指南
局限性
- 不保护动态脚本:当脚本内容动态生成(如服务器端渲染的JSONP)时,无法预计算哈希。
- CDN升级后需同步更新:一旦CDN文件内容变化(即使只是修复一个bug),所有引用该文件且使用了旧哈希的页面都会报错。
- 跨域严格性:如果CDN返回了错误的CORS头部,SRI验证不会触发,直接导致资源无法加载。
- 不支持
<iframe>:SRI目前仅适用于<script>、<link>和<img>(部分浏览器限制)。
避坑指南
- 只对不可变资源使用SRI:例如固定版本的库文件(
jquery@3.6.0),不要对开发者自己生成的动态主文件使用。 - 使用Subresource Integrity工具生成哈希后,务必保存原始文件:若CDN因故更换文件(如服务商升级加密算法),你需要重新计算哈希。
- 不要对
<script>innerHTML</script>内联脚本使用SRI:内联脚本本身无法被SRI验证。 - CDN必须支持CORS:
crossorigin="anonymous"要求CDN返回Access-Control-Allow-Origin: *头部,否则浏览器会直接拒绝加载。
SRI常见问答
Q1:SRI能防止XSS攻击吗?
不能,SRI只验证资源是否被篡改,不防止跨站脚本攻击本身——XSS攻击通常通过注入恶意脚本标签实现,SRI对此无能为力。
Q2:如果我同时引用多个CDN,每个都需要SRI吗?
是的,每个通过<script>或<link>加载的外部资源,都可以(且应该)独立设置integrity属性。
Q3:使用npm包管理器,还需要SRI吗?
需要,npm安装的包可能被开发者本地恶意篡改,或者node_modules中的文件被第三方替换,建议使用npm的integrity校验机制(package-lock.json中的hashes字段),但浏览器不识别该机制,仍需SRI。
Q4:如果CDN宕机,SRI会怎么样?
浏览器会报资源加载失败(网络错误),然后执行onerror回调,SRI不会影响网络请求本身。
Q5:SRI的哈希值应该存储在何处?
最佳实践是:将哈希值作为构建产物的一部分,存储在JSON配置文件或环境变量中,由构建工具自动注入到HTML模板中,不要手动复制粘贴到HTML文件——容易出错且难以维护。
Q6:如何排查SRI失败的原因?
- 确认CDN返回的
Content-Type是否与预期一致。 - 检查
integrity属性写法是否正确(注意sha384-中横线后不能有空格)。 - 在浏览器控制台查看网络请求的响应,确认实际文件内容是否与计算哈希时的文件一致。
Q7:SRI会影响SEO吗?
不直接影响,但若SRI配置错误导致页面关键资源加载失败,可能间接影响页面渲染速度和可用性,从而被搜索引擎降权,建议使用<noscript>或备用资源做降级处理。
Q8:SRI与preload、preconnect等预加载机制冲突吗?
不冲突,你可以正常使用<link rel="preload">预加载资源,并在实际的<script>标签中设置integrity属性,预加载不会执行资源,所以不会触发SRI验证。
Q9:有没有SRI的浏览器扩展?
有,例如Chrome的“Subresource Integrity”扩展,可以快速生成当前页面引用资源的SRI哈希。
Q10:是否需要为所有第三方库添加SRI?
推荐对以下资源添加:
- 核心UI库(如React、Vue、jQuery)
- 分析/监控类脚本(纯被动采集,但防止注入恶意代码)
- 广告脚本(广告SDK可能动态生成内容,但大厂通常提供完整的SRI支持)
不推荐对用户上传的自定义脚本、服务器端动态生成的脚本使用SRI。
为什么SRI是现代Web安全必修课
在供应链攻击日益猖獗的今天,依赖CDN的网站如果不使用SRI,等于将大门钥匙交给了第三方,SRI以极低的成本(仅需生成一次哈希值,嵌入一个属性)就消除了“CDN被攻破”这一高危风险。
关键行动点:
- 立即为所有生产环境中的第三方JS/CSS资源添加
integrity属性 - 将SRI纳入CI/CD流程,构建时自动生成哈希
- 定期检查CDN资源是否被意外更新(推荐使用
ci-build等工具对比哈希变化)
SRI不是可选项——它是现代Web安全的“安全带”。你的网站,安全上路了吗?