ASP.NET Core Blazor 静态服务器端呈现的威胁缓解指南

本文介绍开发人员在使用静态服务器端呈现开发 Blazor Web App 时应考虑的安全注意事项。

Blazor 将三个不同的模型组合在一个中,用于编写交互式 Web 应用。 传统的服务器端呈现,这是基于 HTTP 的请求/响应模型。 交互式服务器端呈现,它是基于 SignalR 的呈现模型。 最后,客户端呈现,它是基于 WebAssembly 的呈现模型。

当交互式组件以某种受支持的呈现模式进行呈现时,为交互式呈现模式定义的所有常规安全注意事项都适用于 Blazor Web App。 以下部分介绍了特定于 Blazor Web App 中非交互式服务器端呈现的安全注意事项,以及呈现模式相互交互时适用的特定方面。

服务器端呈现的一般注意事项

服务器端呈现 (SSR) 模型基于 HTTP 的传统请求/响应模型。 因此,SSR 与请求/响应 HTTP 之间存在共同关注的领域。 常规安全注意事项和必须成功缓解的特定威胁。 该框架提供用于管理其中一些威胁的内置机制,但其他威胁特定于应用代码,必须由应用处理。 这些威胁可以按如下所示进行分类:

  • 身份验证和授权:应用必须确保用户经过身份验证并有权访问应用及其公开的资源。 该框架提供用于身份验证和授权的内置机制,但应用必须确保正确配置和使用机制。 身份验证和授权的内置机制包含在Blazor文档的服务器安全节点ASP.NET 核心文档的安全和Identity节点帐号,因此此处不会介绍它们。

  • 输入验证和清理:在使用之前,必须验证和清理来自客户端的所有输入。 否则,应用可能会受到攻击,例如 SQL 注入、跨站脚本、跨网站请求伪造、开放重定向和其他形式的攻击。 输入可能来自请求中的任何位置。

  • 会话管理:正确管理用户会话对于确保应用不会受到攻击(例如会话修复、会话劫持和其他攻击)至关重要。 会话中存储的信息必须得到适当的保护和加密,并且应用的代码必须防止恶意用户猜测或操作会话。

  • 错误处理和日志记录:应用必须确保正确处理和记录错误。 否则,应用可能会受到攻击,例如信息泄露。 当应用在响应中返回敏感信息或应用返回可用于攻击应用的数据的详细错误消息时,可能会发生这种情况。

  • 数据保护:敏感数据必须得到适当的保护,其中包括在 WebAssembly 上运行时的应用逻辑,因为可以轻松对它执行反向工程。

  • 拒绝服务:应用必须确保它不会受到攻击,例如拒绝服务。 例如,当应用未得到正确保护,可能受暴力破解攻击时,或操作可能导致应用消耗过多资源时,就会发生这种情况。

输入验证和清理

从客户端到达的所有输入都必须被视为不可信的,除非其中的信息是在服务器上生成并受到保护,例如 CSRF 令牌、身份验证 cookie、会话标识符或受身份验证加密保护的任何其他有效负载。

输入通常通过绑定过程(例如通过 [SupplyParameterFromQuery] 属性[SupplyParameterFromForm] 属性)提供给应用。 在处理此输入之前,应用必须确保数据有效。 例如,在将表单数据映射到组件属性时,应用必须确认没有绑定错误。 否则,应用可能会处理无效数据。

如果输入用于执行重定向,应用必须确保输入有效,并且它没有指向被视为无效的域或应用基路径中的无效子路径。 否则,应用可能会受到重定向攻击,其中网络攻击者可以创建将用户重定向到恶意站点的链接。

如果输入用于执行数据库查询,则应用必须确认输入有效,并且它不受 SQL 注入攻击的威胁。 否则,攻击者可能能够创建一个恶意查询,该查询可用于从数据库中提取信息或修改数据库。

对于可能来自用户输入的数据,还必须先进行清理,然后再添加到响应中。 例如,输入可能包含可用于执行跨站脚本攻击的 HTML 或 JavaScript,这些攻击可用于从用户处提取信息或代表用户执行操作。

该框架提供以下机制来帮助进行输入验证和清理:

  • 验证所有绑定表单数据是否基本正确。 如果无法分析输入,绑定过程会报告应用在对数据执行任何操作之前就可以发现的错误。 在调用 OnValidSubmit 表单回调之前,内置 EditForm 组件会考虑到这一点。 如果存在一个或多个绑定错误,Blazor 会阻止执行回调。
  • 该框架使用防伪令牌来保护跨网站请求伪造攻击。 有关详细信息,请参阅 ASP.NET Core Blazor 身份验证和授权ASP.NET Core Blazor 表单概述

在执行给定操作时,必须在服务器上验证所有输入和权限,以确保数据在该时间有效且准确,且允许用户执行该操作。 此方法与为交互式服务器端呈现提供的安全指南一致。

会话管理

会话管理由框架处理。 该框架使用会话 cookie 标识用户会话。 使用 ASP.NET 核心数据保护 API 保护会话 cookie。 浏览器上运行的 JavaScript 代码无法访问会话 cookie,用户无法轻松猜测或操作该会话。

对于其他会话数据(例如存储在服务中的数据),会话数据应存储在作用域服务中,因为作用域服务对于给定用户会话是唯一的,单一实例服务则相反,它在给定过程实例中供所有用户会话共享。

在 SSR 方面,在大多数情况下,作用域和暂时性服务之间没有太大的区别,因为服务的生存期仅限于单个请求。 在两种情况中存在差异:

  • 如果在请求期间将服务注入多个位置或在不同时间注入。
  • 如果服务可能在交互式服务器上下文中使用,且服务在多个呈现中幸存下来,以及服务的范围限定为用户会话这一基础。

错误处理和日志记录

该框架在框架级别为应用提供内置日志记录。 该框架会记录重要事件,例如表单的防伪令牌无法验证、根组件开始呈现,以及调度操作。 该应用负责记录任何其他可能很重要的事件。

该框架在框架级别为应用提供内置错误处理。 该框架处理在组件呈现过程中发生的错误,并使用错误边界机制显示友好的错误消息,或允许错误出现在配置为呈现错误页的异常处理中间件。

在响应开始发送到客户端后流式呈现期间发生的错误会作为一般错误消息显示在最终响应中。 有关错误原因的详细信息仅在开发过程中提供。

ASP.NET Core 数据保护

该框架提供保护给定用户会话敏感信息的机制,并确保内置组件使用这些机制来保护敏感信息,例如在使用 cookie 身份验证时保护用户 identity。 在框架处理的方案之外,开发人员代码负责保护其他特定于应用的信息。 执行此操作的最常见方法是通过 ASP.NET Core 数据保护 (DP) API 或任何其他形式的加密。 一般情况下,应用负责:

  • 确保用户无法检查或修改其他用户的私有信息。
  • 确保用户无法修改其他用户的用户数据,例如内部标识符。

在数据保护方面,必须清楚地了解代码的执行位置。 对于静态服务器端呈现(静态 SSR)和交互式服务器端呈现模式,代码存储在服务器上,永远不会到达客户端。 对于交互式 WebAssembly 呈现模式,应用代码始终会到达客户端,这意味着应用代码中存储的任何敏感信息都可供有权访问应用的任何人使用。 混淆处理和其他类似的代码“保护”技术无效。 代码到达客户端后,可以对其进行反向工程以提取敏感信息。

拒绝服务

在服务器级别,该框架对请求/响应参数(例如请求的最大大小和标头大小)提供限制。 对于应用代码,Blazor 的表单映射系统定义了类似于 MVC 模型绑定系统定义的限制:

  • 最大错误数限制。
  • 活页夹的最大递归深度限制。
  • 集合中绑定的最大元素数限制。

此外,还为窗体定义了限制,例如窗体键大小上限和值大小,以及条目数上限。

一般情况下,应用必须评估请求触发服务器非对称工作量的可能性。 例如,当用户发送由 N 参数化的请求,并且服务器在响应中执行一个操作,该操作费用为 N 倍,其中 N 是用户控制并可无限期增长的参数。 通常,应用必须对它愿意处理的最大 N 施加限制,或确保任何操作的费用小于、相等或高于请求的常量因子。

这方面与客户端执行的工作和服务器执行的工作之间的增长差异的关联性大于特定的 1→N 比较。 例如,客户端可能会提交一个工作项(将元素插入列表),该工作项需要 N 个时间单位才能执行,但服务器需要 N2 来处理(因为它可能正在执行非常天真的事情)。 N 和 N2 之间的区别很重要。

因此,服务器必须愿意执行的操作量有限制,且该限制针对于应用。 这方面适用于服务器端的工作负载,因为资源位于服务器上,但在大多数情况下不一定适用于客户端上的 WebAssembly 工作负载。

另一个重要方面是,这不仅保留到 CPU 时间。 它还适用于任何资源,例如内存、网络和和磁盘上的空间。

对于 WebAssembly 工作负载,客户端执行的工作量通常很少,因为客户端通常受客户端上可用资源的限制。 但是,在某些情况下,客户端可能会受到影响,例如,如果应用显示其他用户的数据,并且一个用户能够将数据添加到以下系统:该系统强制显示数据的客户端执行与用户添加的数据量不成比例的工作量。

  • 确保对用户进行身份验证,且用户有权访问应用及其公开的资源。
  • 在使用来自客户端的任何输入之前验证并清理输入。
  • 正确管理用户会话,以确保不会错误地跨用户共享状态。
  • 正确处理和记录错误,以避免公开敏感信息。
  • 记录应用中的重要事件,以识别用户执行的潜在问题和审核操作。
  • 使用 ASP.NET 核心数据保护 API 或其中一个可用组件(Microsoft.AspNetCore.Components.Server.ProtectedBrowserStoragePersistentComponentState)保护敏感信息。
  • 确保应用了解可由给定请求使用的资源,并配置了限制以避免拒绝服务攻击。