ASP.NET Core Blazor WebAssembly .NET 运行时和应用捆绑包缓存

注意

此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

对于当前版本,请参阅此文的 .NET 8 版本

当 Blazor WebAssembly 应用程序在浏览器中加载时,该应用程序将从服务器下载启动资源:

  • 用于启动应用程序的 JavaScript 代码
  • .NET 运行时和程序集
  • 区域设置特定的数据

除了 Blazor 的启动资源文件 (blazor.boot.json) 外,WebAssembly .NET 运行时和应用捆绑包文件都缓存在客户端上。 blazor.boot.json 文件包含构成必须下载的应用的文件清单,以及用于检测任何启动资源是否已被更改的文件内容的哈希。 Blazor 使用浏览器缓存 API 缓存下载的文件。

当 Blazor WebAssembly 下载应用的启动文件时,它会指示浏览器对响应执行完整性检查。 Blazor 为 DLL (.dll)、WebAssembly (.wasm) 和 blazor.boot.json 文件中的其他文件发送 SHA-256 哈希值。 缓存的文件的文件哈希与 blazor.boot.json 文件中的哈希进行比较。 对于具有匹配哈希的缓存文件,Blazor 使用缓存的文件。 否则,会从服务器请求文件。 在一个文件下载完成后,它的哈希值会被再次检查以验证完整性。 如果任何已下载文件的完整性检查失败,浏览器会生成错误。

Blazor 用于管理文件完整性的算法:

  • 确保应用不会出现加载不一致文件集的风险,例如,在用户正在下载应用程序文件时,将新部署应用到 Web 服务器的情况。 不一致的文件可能会导致应用出现故障。
  • 确保用户的浏览器从不缓存不一致或无效的响应,这些响应可阻止应用启动,即使用户手动刷新页面也是如此。
  • 可以安全地缓存响应,在预期的 SHA-256 哈希本身发生更改之前,不检查服务器端更改,这使得后续页面加载涉及更少的请求,可以快速完成。

如果 Web 服务器返回的响应与预期的 SHA-256 哈希不匹配,类似于以下示例的错误将显示在浏览器的开发人员控制台中:

未能使用计算出的 SHA-256 完整性“IIa70iwvmEg5WiDV17OpQ5eCztNYqL186J56852RpJY=”在资源“https://myapp.example.com/_framework/MyBlazorApp.dll”的“integrity”属性中找到有效摘要。 资源已被阻止。

在大多数情况下,警告并不表示完整性检查存在问题。 相反,警告通常表示存在一些其他问题。

注意

指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)

诊断完整性问题

生成应用时,生成的 blazor.boot.json 清单将描述生成输出生成时启动资源的 SHA-256 哈希。 只要 blazor.boot.json 中的 SHA-256 哈希与传递到浏览器的文件相匹配,完整性检查就会通过。

此失败的常见原因包括:

  • Web 服务器的响应是一个错误(例如,“404 - 找不到”或“500 - 内部服务器错误”),而不是浏览器所请求的文件。 浏览器会将其报告为完整性检查失败,而不是响应失败。
  • 在文件生成和传递到浏览器之间已更改文件的内容。 下面可能会发生这种情况:
    • 你或生成工具手动修改生成输出的情况。
    • 部署过程的某个方面修改了文件的情况。 例如,在使用基于 Git 的部署机制时,请记住,如果你在 Windows 上提交文件并在 Linux 上检查它们,则 Git 会以透明方式将 Windows 样式的行尾转换为 Unix 样式的行尾。 更改文件行尾将更改 SHA-256 哈希。 若要避免此问题,请考虑使用 .gitattributes 将生成项目视为 binary 文件
    • Web 服务器在提供文件内容的过程中对其进行修改。 例如,某些内容分发网络 (CDN) 会自动尝试缩小 HTML,从而对其进行修改。 可能需要禁用此类功能。
  • blazor.boot.json 文件无法正确加载或未正确缓存在客户端上。 常见原因包括以下任一种:
    • 自定义开发人员代码配置错误或出现故障。
    • 一个或多个中间缓存层配置错误。

若要诊断哪些功能适用于你的情况,请执行执行操作:

  1. 通过读取错误消息来记下哪个文件触发错误。
  2. 打开浏览器的开发人员工具,然后在“网络”选项卡中查找。如有必要,请重新加载页面以查看请求和响应的列表。 在该列表中查找触发错误的文件。
  3. 检查响应中的 HTTP 状态代码。 如果服务器返回除“200 - 正常”(或其他 2xx 状态代码)以外的任何内容,则需要诊断服务器端问题。 例如,状态代码 403 表示存在授权问题,而状态代码 500 表示服务器以未指定的方式失败。 请参阅服务器端日志以诊断和修复应用。
  4. 如果资源的状态代码为“200 - 正常”,请在浏览器的开发人员工具中查看响应内容,并检查内容是否与预期的数据匹配。 例如,常见问题是错误配置了路由,因此请求甚至返回其他文件的 index.html 数据。 请确保对 .wasm 请求的响应是 WebAssembly 二进制文件,对 .dll 请求的响应是 .NET 程序集二进制文件。 如果不是,则需要诊断服务器端路由问题。
  5. 搜索以验证应用的已发布和已部署输出,并提供完整性 PowerShell 脚本故障排除

如果确认服务器返回看似正确的数据,则必须在生成文件和传递文件之间修改内容。 若要对此进行调查,请执行以下操作:

  • 如果在生成文件后修改文件,请检查生成工具链和部署机制。 例如,在 Git 转换文件行尾时,如前所述。
  • 如设置为动态修改响应(例如,尝试缩小 HTML),请检查 Web 服务器或 CDN 配置。 Web 服务器可以实现 HTTP 压缩(例如,返回 content-encoding: brcontent-encoding: gzip),因为这不会影响解压缩后的结果。 但是,Web 服务器不可以修改未压缩的数据。

完整性 PowerShell 脚本故障排除

使用 integrity.ps1 PowerShell 脚本来验证已发布和已部署的 Blazor 应用。 当应用出现 Blazor 框架无法识别的完整性问题时,该脚本将作为起点提供给 PowerShell Core 7 或更高版本。 应用可能需要自定义脚本,包括在 7.2.0 版之后的 PowerShell 版本上运行时。

此脚本将检查 publish 文件夹中的文件,并从部署的应用中下载这些文件,以检测包含完整性哈希的不同清单中的问题。 这些检查应检测最常见的问题:

  • 你修改了已发布的输出中的文件,但未实现它。
  • 应用未正确部署到部署目标,或者在部署目标的环境中发生了更改。
  • 部署的应用与发布应用的输出之间存在差异。

在 PowerShell 命令行中使用以下命令调用脚本:

.\integrity.ps1 {BASE URL} {PUBLISH OUTPUT FOLDER}

在下面的示例中,脚本在位于 https://localhost:5001/ 的本地运行的应用上执行:

.\integrity.ps1 https://localhost:5001/ C:\TestApps\BlazorSample\bin\Release\net6.0\publish\

占位符:

  • {BASE URL}:已部署的应用的 URL。 尾部反斜杠 (/) 是必需项。
  • {PUBLISH OUTPUT FOLDER}:应用的 publish 文件夹的路径,或已发布的用于部署应用的位置。

注意

克隆 dotnet/AspNetCore.Docs GitHub 存储库时,integrity.ps1 脚本可能会被 Bitdefender 或系统上存在的另一个病毒扫描程序隔离。 通常,该文件被病毒扫描程序的启发式扫描技术捕获,该技术只查找文件中可能指示存在恶意软件的模式。 若要防止病毒扫描程序隔离该文件,请在克隆存储库之前向病毒扫描程序添加一个例外。 以下示例是 Windows 系统上脚本的一个典型路径。 可以根据需要为其他系统调整路径。 占位符 {USER} 是用户的路径段。

C:\Users\{USER}\Documents\GitHub\AspNetCore.Docs\aspnetcore\blazor\host-and-deploy\webassembly\_samples\integrity.ps1

警告:创建病毒扫描程序例外是危险操作,只有在你确定文件是安全的情况下才可以进行。

将文件的校验和与有效校验和值进行比较并不能保证文件的安全,但以维护校验和值的方式修改文件对于恶意用户来说并不简单。 因此,校验和作为一种常规安全方法很有用。 将本地 integrity.ps1 文件的校验和与以下值之一进行比较:

  • SHA256:32c24cb667d79a701135cb72f6bae490d81703323f61b8af2c7e5e5dc0f0c2bb
  • MD5:9cee7d7ec86ee809a329b5406fbf21a8

通过以下命令在 Windows OS 上获取文件的校验和。 为 {PATH AND FILE NAME} 占位符提供路径和文件名,并指明为 {SHA512|MD5} 占位符生成的校验和类型,可以是 SHA256,也可以是 MD5

CertUtil -hashfile {PATH AND FILE NAME} {SHA256|MD5}

如果你有任何理由担心校验和验证在你的环境中不够安全,请咨询组织的安全领导以获得指导。

有关详细信息,请参阅 Microsoft Defender 防病毒的威胁防护概述

禁用非 PWA 应用的资源缓存和完整性检查

在大多数情况下,不要禁用完整性检查。 禁用完整性检查并不能解决导致意外响应的根本问题,并且会导致丢失前面列出的权益。

在某些情况下,Web 服务器无法用于返回一致的响应,但别无选择,只能暂时禁用完整性检查,直到根本问题得到解决。

若要禁用完整性检查,请将以下内容添加到 Blazor WebAssembly 应用的项目文件 (.csproj) 中的属性组:

<BlazorCacheBootResources>false</BlazorCacheBootResources>

BlazorCacheBootResources 还会根据 SHA-256 哈希禁用 Blazor 缓存 .dll.wasm 和其他文件的默认行为,因为属性指示无法依靠 SHA-256 哈希来确保正确性。 即使有此设置,浏览器的普通 HTTP 缓存仍可能会缓存这些文件,但是否发生这种情况取决于你的 Web 服务器配置和它所提供的 cache-control 标头。

注意

BlazorCacheBootResources 属性不会禁用渐进式 Web 应用程序 (PWA) 的完整性检查。 有关 PWA 的相关指南,请参阅禁用 PWA 的完整性检查部分。

我们无法提供需要禁用完整性检查的场景的详尽列表。 服务器可以在 Blazor 框架范围之外以任意方式应答请求。 该框架提供了 BlazorCacheBootResources 设置,使应用可以运行,但代价是不能保证应用可以提供的完整性。 同样,我们不建议禁用完整性检查,尤其是对于生产部署。 开发人员应设法解决导致完整性检查失败的根本完整性问题。

可能导致完整性问题的几个常见情况如下:

  • 在 HTTP 上运行,无法检查完整性。
  • 部署过程在发布后以任何方式修改了文件。
  • 主机以任何方式修改了文件。

禁用 PWA 的资源缓存和完整性检查

Blazor 的渐进式 Web 应用程序 (PWA) 模板包含建议的 service-worker.published.js 文件,该文件负责获取和存储应用程序文件以供脱机使用。 这是普通应用启动机制的独立进程,具有其自己单独的完整性检查逻辑。

service-worker.published.js 文件中,出现以下行:

.map(asset => new Request(asset.url, { integrity: asset.hash }));

若要禁用完整性检查,请通过将该行更改为以下行来删除 integrity 参数:

.map(asset => new Request(asset.url));

同样,禁用完整性检查意味着会丢失完整性检查提供的安全保证。 例如,如果用户的浏览器在你部署新版本的那一刻缓存应用,则会存在风险,它可能会缓存旧部署中的某些文件和新部署中的某些文件。 如果发生这种情况,则在部署进一步更新之前,应用程序会在中断状态下停滞。

其他资源

启动资源加载