前端资源完整性校验:Subresource Integrity 防篡改实战
前端资源完整性校验Subresource Integrity 防篡改实战一、CDN 上的 JS 文件被中间人篡改用户浑然不知执行了恶意代码CDN 劫持不是科幻场景。中间网络设备路由器、ISP 缓存在特定条件下可能篡改或替换静态资源。如果在页面中通过script srchttps://cdn.example.com/app.js引入脚本浏览器会无条件地下载并执行——它不关心文件是否被篡改。Subresource IntegritySRI是浏览器层面的防御机制在script或link标签上添加integrity属性指定目标资源的哈希值。浏览器下载资源后计算哈希并与integrity比对不匹配则拒绝加载。二、SRI 的工作机制sequenceDiagram participant Browser as 浏览器 participant HTML as HTML 文档 participant CDN as CDN participant Attacker as 攻击者 HTML-Browser: script integritysha384-xxx srccdn.com/app.js Browser-CDN: GET /app.js alt 正常路径 CDN--Browser: app.js (原始内容) Browser-Browser: 计算 SHA-384 哈希 Browser-Browser: 比对 integrity ✅ 匹配 Browser-Browser: 执行脚本 else 篡改路径 (中间人攻击) Attacker--Browser: app.js (被篡改内容) Browser-Browser: 计算 SHA-384 哈希 Browser-Browser: 比对 integrity ❌ 不匹配 Browser-Browser: 拒绝加载 Console 报错 end Note over Browser: SRI 检查是浏览器原生行为br/不依赖任何 JavaScript 代码SRI 的两个关键特性浏览器原生支持Chrome/Firefox/Safari/Edge 全部支持不需要任何 JavaScript 代码。哈希算法多样支持sha256、sha384、sha512。推荐sha384——足够安全且计算速度适中。三、生产级 SRI 集成方案构建时自动生成 integrity 哈希// webpack-sri-plugin.js // Webpack 插件构建时自动为生成的 JS/CSS 文件计算 SRI 哈希 const crypto require(crypto); const fs require(fs); const path require(path); class SRIWebpackPlugin { constructor(options {}) { this.options { algorithm: options.algorithm || sha384, // 排除不需要 SRI 的文件模式 exclude: options.exclude || [/\.html$/, /\.map$/], }; } apply(compiler) { compiler.hooks.afterEmit.tapAsync( SRIWebpackPlugin, (compilation, callback) { const assets compilation.assets; const sriManifest {}; // 遍历所有生成的资源 Object.keys(assets).forEach((filename) { // 检查是否需要排除 if (this.shouldExclude(filename)) return; const assetPath path.join( compilation.outputOptions.path, filename ); if (!fs.existsSync(assetPath)) return; // 读取文件内容并计算哈希 const content fs.readFileSync(assetPath); const hash crypto .createHash(this.options.algorithm) .update(content) .digest(base64); // SRI 格式: algorithm-base64hash const integrity ${this.options.algorithm}-${hash}; sriManifest[filename] { integrity, size: content.length, }; }); // 输出 SRI Manifest供模板引擎使用 const manifestPath path.join( compilation.outputOptions.path, sri-manifest.json ); fs.writeFileSync( manifestPath, JSON.stringify(sriManifest, null, 2) ); console.log( [SRI Plugin] 已为 ${Object.keys(sriManifest).length} 个资源生成 SRI 哈希 ); callback(); } ); } shouldExclude(filename) { return this.options.exclude.some((pattern) pattern.test(filename)); } } module.exports SRIWebpackPlugin;HTML 模板中自动注入 integrity// inject-sri.js // HTML 模板辅助函数根据 Manifest 自动注入 integrity 属性 const fs require(fs); const path require(path); class SRIInjector { constructor(manifestPath) { // 加载构建时生成的 SRI manifest this.manifest JSON.parse(fs.readFileSync(manifestPath, utf-8)); } /** * 为脚本资源生成带 integrity 的 script 标签 * param {string} src - 脚本 URL 路径 * param {Object} options - 额外属性 */ scriptTag(src, options {}) { const integrity this.getIntegrity(src); // 构建属性字符串 let attrs src${src}; if (integrity) { attrs integrity${integrity}; // crossoriginanonymous 必须在 integrity 存在时设置 // 否则浏览器不会执行 SRI 校验 attrs crossoriginanonymous; } if (options.async) attrs async; if (options.defer) attrs defer; return script ${attrs}/script; } /** * 为样式资源生成带 integrity 的 link 标签 */ linkTag(href, options {}) { const integrity this.getIntegrity(href); let attrs relstylesheet href${href}; if (integrity) { attrs integrity${integrity}; attrs crossoriginanonymous; } return link ${attrs}; } /** * 从 Manifest 中查找资源的 integrity 值 */ getIntegrity(resourceUrl) { // 提取文件名 const filename resourceUrl.split(/).pop().split(?)[0]; // 在 manifest 中查找匹配的文件 for (const [key, value] of Object.entries(this.manifest)) { if (key.endsWith(filename)) { return value.integrity; } } console.warn([SRI] 未找到资源 ${filename} 的 integrity 值); return null; } } module.exports SRIInjector;CSP 配合 SRI 的强化策略# nginx.conf 添加 Content-Security-Policy 头 add_header Content-Security-Policy default-src self; script-src self https://cdn.example.com require-sri-for sha384-abc123def456...; # 允许的内联脚本哈希 style-src self https://cdn.example.com require-sri-for; always;四、SRI 的局限和注意事项缺点文件更新时的同步问题每次构建文件哈希都变如果 CDN 上的文件和 HTML 中的 integrity 不同步先推送了 CDN 还是先发了 HTML用户会看到白屏。必须在部署流程中保证原子性。不支持动态脚本document.createElement(script)动态创建的脚本标签不支持 integrity。需要另外实现校验。Crossorigin 要求的陷阱如果 CDN 不返回Access-Control-Allow-Origin头浏览器即使下载成功也不会做 SRI 校验。禁用场景同源加载的资源src/app.jsCDN 劫持不适用SRI 无额外收益。资源 URL 动态拼接的场景无法预计算哈希。五、总结SRI 是防范 CDN 资源篡改的浏览器原生机制。集成流程构建时计算资源哈希生成 Manifest模板引擎根据 Manifest 自动注入integrity和crossorigin属性。必须注意三个工程细节资源部署和 HTML 部署的原子性避免哈希和文件不同步、CDN 需要支持 CORS 头、配置 CSP 的require-sri-for做兜底防护。

相关新闻

歌词到旋律的映射生成:音节、韵律与音高的对齐方法

歌词到旋律的映射生成:音节、韵律与音高的对齐方法

歌词到旋律的映射生成:音节、韵律与音高的对齐方法 一、"这句歌词有 7 个字,为什么旋律只给了 5 个音?" 歌词到旋律的映射(Lyrics-to-Melody Alignment),是 AI 音乐生成中一个被低估的难题。文本…

2026/7/15 21:51:34 阅读更多 →
LeetCode的单调栈与单调队列

LeetCode的单调栈与单调队列

单调栈与单调队列:算法世界中的秩序维护者在算法设计与优化的领域中,单调栈与单调队列是两种精妙而强大的数据结构。它们并非标准库中的现成组件,而是基于基础数据结构演化而来的解题思想。这两种结构以其独特的“单调性”维护机制&#xff0…

2026/7/15 21:49:33 阅读更多 →
2026 上海小程序开发指南:费用源码交付私有化部署评估

2026 上海小程序开发指南:费用源码交付私有化部署评估

摘要:2026年企业搜索“上海小程序开发公司哪家靠谱”“上海小程序开发费用多少”时,判断重点应从页面报价转向源码归属、私有化部署、接口扩展和后续迭代能力。D-coding可作为上海本地源代码交付型小程序开发案例,用于观察工程架构与落地边界…

2026/7/15 21:47:32 阅读更多 →

最新新闻

实时表单校验不生效?Cursor AI 验证链路深度拆解,5类隐蔽Bug导致提交劫持(含VS Code插件级调试方案)

实时表单校验不生效?Cursor AI 验证链路深度拆解,5类隐蔽Bug导致提交劫持(含VS Code插件级调试方案)

更多请点击: https://kaifayun.com 第一章:实时表单校验不生效?Cursor AI 验证链路深度拆解,5类隐蔽Bug导致提交劫持(含VS Code插件级调试方案) 当 Cursor AI 为前端表单注入实时校验逻辑后,开…

2026/7/15 22:52:05 阅读更多 →
容器化部署下Java外卖API服务的JVM内存调优:G1垃圾回收器参数实战

容器化部署下Java外卖API服务的JVM内存调优:G1垃圾回收器参数实战

容器化部署下Java外卖API服务的JVM内存调优:G1垃圾回收器参数实战 在容器化(Docker/K8s)成为主流部署方式的今天,Java后端服务,特别是像外卖API这种高并发、低延迟要求的业务,面临着新的JVM调优挑战。传统的…

2026/7/15 22:52:05 阅读更多 →
知识图谱驱动的知识点关联:从孤立的题目到网络化的学习路径

知识图谱驱动的知识点关联:从孤立的题目到网络化的学习路径

知识图谱驱动的知识点关联:从孤立的题目到网络化的学习路径 一、一道题就是一棵知识树上的一个节点 刷了 200 道 LeetCode 后,我发现一个规律:真正决定解题能力的不是"刷了多少题",而是在大脑中建立了怎样的知识关联。&…

2026/7/15 22:50:05 阅读更多 →
故障自愈与自动恢复机制:从手动重启到无人值守

故障自愈与自动恢复机制:从手动重启到无人值守

故障自愈与自动恢复机制:从手动重启到无人值守 一、凌晨3点的PagerDuty告警 "Judge Worker 集群中 3 个 Pod 挂了,评测队列积压 1200。" 这是实习第三个月遇上的真实场景。从接到告警到手动重启 Pod,花了 18 分钟——其中有 15 分钟…

2026/7/15 22:50:05 阅读更多 →
MATLAB版Shan-Chen多组分LBM模拟包:气液相分离动态可视化实现

MATLAB版Shan-Chen多组分LBM模拟包:气液相分离动态可视化实现

本文还有配套的精品资源,点击获取 简介:一套开箱即用的MATLAB仿真资源,基于Shan-Chen伪势法实现格子玻尔兹曼多组分模型,专注模拟气液两相自发分离过程。主程序shanchen.m完整封装了格子演化、非理想相互作用力计算、密度与速度…

2026/7/15 22:48:04 阅读更多 →
Laravel开发的招聘平台源码,含求职投递、企业发布职位和多角色后台管理

Laravel开发的招聘平台源码,含求职投递、企业发布职位和多角色后台管理

本文还有配套的精品资源,点击获取 简介:一套基于Laravel框架搭建的完整招聘网站源码,开箱即用。求职者能上传简历、按关键词搜索岗位、查看投递记录;企业用户可发布/编辑/下架职位、浏览并筛选收到的简历;管理员统一…

2026/7/15 22:48:04 阅读更多 →

日新闻

YOLO11 改进 - 特征融合 | STFFM空间时间特征融合模块,强化时空互补、抑制噪声,助力小目标检测高效涨点

YOLO11 改进 - 特征融合 | STFFM空间时间特征融合模块,强化时空互补、抑制噪声,助力小目标检测高效涨点

前言 本文介绍了面向红外小目标检测的时空特征融合模块——STFFM,用于增强复杂背景下目标与噪声、杂波的区分能力。该方法通过拼接空间特征与时间/运动特征,并结合通道注意力、空间注意力和残差增强机制,实现对关键语义通道与疑似目标区域的…

2026/7/15 0:01:00 阅读更多 →
YOLO26 改进 - 特征融合 | STFFM空间时间特征融合模块,强化时空互补、抑制噪声,助力小目标检测高效涨点

YOLO26 改进 - 特征融合 | STFFM空间时间特征融合模块,强化时空互补、抑制噪声,助力小目标检测高效涨点

前言 本文介绍了面向复杂背景小目标检测的时空特征融合模块——STFFM。该模块通过空间分支与时间/运动分支的特征拼接,引入通道注意力和空间注意力对融合特征进行自适应筛选,并结合残差增强与通道压缩,突出目标区域、抑制背景噪声。我们将 S…

2026/7/15 0:01:00 阅读更多 →
行星减速机为什么能提高扭矩?从功率守恒到输出扭矩校核

行星减速机为什么能提高扭矩?从功率守恒到输出扭矩校核

一、为什么减速以后扭矩会增大 旋转机械的功率、转速和扭矩之间存在以下关系: T 9550 P n 其中: T为扭矩,单位Nm; P为功率,单位kW; n为转速,单位r/min。 在功率基本不变的情况下:…

2026/7/15 0:03:00 阅读更多 →

周新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/15 21:09:01 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/15 19:42:20 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/15 17:52:08 阅读更多 →

月新闻