Featured image of post 子资源完整性:保护您的 CDN 依赖项Featured image of post 子资源完整性:保护您的 CDN 依赖项

子资源完整性:保护您的 CDN 依赖项

Web 安全子资源完整性 (SRI) 的完整指南:哈希生成、跨源配置、构建时集成、CSP 关联和监控。

子资源完整性 (SRI) 是一项安全功能,可让浏览器验证从 CDN 或第三方来源获取的资源是否未被篡改。在供应链攻击的时代——英国航空公司 Magecart 漏洞、Polyfill.io 泄露以及众多 CDN 事件——SRI 提供加密保证,确保您的页面加载的资源正是您想要的。

社会责任投资如何运作

当您将 integrity 属性添加到 <script><link rel="stylesheet"> 标记时,浏览器会计算所获取资源的哈希值并将其与属性值进行比较。如果它们不匹配,浏览器将拒绝执行或应用该资源。

<script
  src="https://cdn.example.com/library.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
></script>

当资源的多个版本可接受时,多个哈希(逗号分隔)允许优雅的回退:

<script
  src="https://cdn.example.com/app.js"
  integrity="sha384-ABC... sha512-XYZ..."
  crossorigin="anonymous"
></script>

跨源资源上的 SRI 需要 crossorigin="anonymous" 属性。如果没有正确的 CORS 标头,浏览器会以不透明模式加载资源,并且无法验证其完整性 - 该资源会被静默忽略,不会出现任何错误。


生成 SRI 哈希值

您可以使用 OpenSSL、在线工具或构建时插件生成 SRI 哈希值:

# OpenSSL command
openssl dgst -sha384 -binary file.js | openssl base64 -A

为了实现自动化,请将 SRI 生成集成到您的构建管道中。构建工具支持成熟:

工具插件/配置
网页包占位符_0
维特vite-plugin-sri 或通过 experimental.renderBuiltUrl 内置
Next.jsnext.config.js 中的 experimental.sri
天文资产组件上内置 integrity 属性
// Next.js SRI configuration
// next.config.js
module.exports = {
  experimental: {
    sri: {
      hash: "sha384",
    },
  },
};

确保在缩小和生成源映射后计算哈希值 - 哈希值必须与最终提供的内容匹配,而不是与开发源匹配。


SRI 和 CSP 相关性

内容安全策略和 SRI 相辅相成。 CSP限制哪些来源可以加载资源; SRI 确保来自允许来源的资源未被修改。它们相结合,为第三方资源加载提供深度防御。

<!-- CSP header -->
Content-Security-Policy:
  script-src https://cdn.example.com 'sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC';
  report-uri https://reporting.example.com/csp-violations

<!-- HTML with SRI -->
<script
  src="https://cdn.example.com/library.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
></script>

使用 CSP 的 report-urireport-to 指令来监视 SRI 违规。不匹配的哈希可能表明 CDN 受损、构建管道问题或中间件进行的内容转换。


监控 SRI 违规行为和高级模式

侦听具有完整性属性的元素上的 error 事件,或使用报告 API 从浏览器收集 SRI 违规报告:

// Client-side SRI violation monitoring
document.querySelectorAll("script[integrity]").forEach((el) => {
  el.addEventListener("error", (event) => {
    fetch("/api/sri-violation", {
      method: "POST",
      body: JSON.stringify({
        src: el.src,
        integrity: el.getAttribute("integrity"),
        timestamp: new Date().toISOString(),
      }),
    });
  });
});

CDN 提供商在 SRI 支持方面有所不同。验证您的 CDN 的功能:

CDNSRI 支持笔记
cdnjs完整为所有库提供哈希值
jsDelivr完整包 API 响应中的哈希值
联合国包装袋通过 ?meta可通过查询参数获取哈希值
Google 托管库部分仅适用于受支持的库

高级 SRI 模式包括用户交互后加载的脚本的动态验证、Web Worker 的 SRI (new Worker("script.js", { integrity: "..." })) 以及 ES 模块分片的导入映射条目的完整性。

// Dynamic SRI verification for runtime-loaded scripts
async function loadWithIntegrity(url, integrity) {
  const response = await fetch(url);
  const buffer = await response.arrayBuffer();
  const hash = await crypto.subtle.digest("SHA-384", buffer);
  const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));
  if (base64 !== integrity.replace("sha384-", "")) {
    throw new Error("Integrity check failed");
  }
  // Execute the script safely
  const blob = new Blob([buffer], { type: "text/javascript" });
  const blobUrl = URL.createObjectURL(blob);
  const script = document.createElement("script");
  script.src = blobUrl;
  document.body.appendChild(script);
}

实施回退策略:使用 SRI 从主 CDN 加载,如果完整性验证失败,则回退到自托管副本。即使 CDN 遭到破坏或内容发生更改,这也可确保您的应用程序保持正常运行。

SRI 是一项易于实现的关键安全控制:生成哈希、添加完整性属性、配置 CORS 标头以及在 CI 中自动生成哈希。结合CSP,为第三方资源加载提供强有力的保护。将 SRI 添加到所有外部资源、自动化流程并主动监控故障。