为 ASP.NET Core Blazor 强制实施内容安全策略
注意
此版本不是本文的最新版本。 有关当前版本,请参阅本文的 .NET 9 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .NET 8 版本。
本文介绍如何将内容安全策略 (CSP) 用于 ASP.NET Core Blazor 应用,以帮助防范跨站脚本 (XSS) 攻击。
跨站脚本 (XSS) 是一种安全漏洞,网络攻击者会将一个或多个恶意客户端脚本放入应用的呈现内容中。 CSP 通过通知浏览器有效的信息来帮助防御 XSS 攻击:
- 已加载内容的源,包括脚本、样式表、图像和插件。
- 页面执行的操作,指定允许的表单 URL 目标。
要将 CSP 应用于应用,开发人员会在一个或多个 Content-Security-Policy
标头或 <meta>
标记中指定多个 CSP 内容安全指令。 有关在启动时将 CSP 应用于使用 C# 代码的应用的指南,请参阅 ASP.NET Core Blazor 启动。
加载页面时,浏览器会对策略进行评估。 浏览器将检查页面的源并确定它们是否满足内容安全指令的要求。 如果资源不符合策略指令,浏览器不会加载资源。 例如,请考虑不允许第三方脚本的策略。 当某个页面的 src
属性中包含带有第三方来源的 <script>
标记时,浏览器将阻止加载该脚本。
大多数新式桌面和移动浏览器(包括 Chrome、Microsoft Edge、Firefox、Opera 和 Safari)都支持 CSP。 建议将 CSP 用于 Blazor 应用。
策略指令
至少为 Blazor 应用指定以下指令和源。 按需添加其他指令和源。 本文的“应用策略”部分中使用了以下指令,其中提供了 Blazor 应用的示例安全策略:
- base-uri:限制页面的
<base>
标记的 URL。 指定self
,以指示应用的来源(包括方案和端口号)是有效源。 - default-src:指示未被策略显式指定的源指令的回退。 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - img-src:指示图像的有效源。
- 指定
data:
,以允许从data:
URL 加载图像。 - 指定
https:
,以允许从 HTTPS 终结点加载图像。
- 指定
- object-src:指示
<object>
、<embed>
和<applet>
标记的有效源。 指定none
以阻止所有 URL 源。 - script-src:指示脚本的有效源。
- 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - 在客户端 Blazor 应用中:
- 指定
wasm-unsafe-eval
以允许客户端 Blazor Mono 运行时正常运行。 - 指定任何其他哈希值以允许加载所需的非框架脚本。
- 指定
- 在服务器端 Blazor 应用中,指定哈希以允许加载所需的脚本。
- 指定
- style-src:指示样式表的有效源。
- 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - 如果应用使用嵌入式样式,则指定
unsafe-inline
以允许使用嵌入式样式。
- 指定
- upgrade-insecure-requests:指示应通过 HTTPS 安全地获取来自不安全 (HTTP) 源的内容 URL。
- base-uri:限制页面的
<base>
标记的 URL。 指定self
,以指示应用的来源(包括方案和端口号)是有效源。 - default-src:指示未被策略显式指定的源指令的回退。 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - img-src:指示图像的有效源。
- 指定
data:
,以允许从data:
URL 加载图像。 - 指定
https:
,以允许从 HTTPS 终结点加载图像。
- 指定
- object-src:指示
<object>
、<embed>
和<applet>
标记的有效源。 指定none
以阻止所有 URL 源。 - script-src:指示脚本的有效源。
- 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - 在客户端 Blazor 应用中:
- 指定
unsafe-eval
以允许客户端 Blazor Mono 运行时正常运行。 - 指定任何其他哈希值以允许加载所需的非框架脚本。
- 指定
- 在服务器端 Blazor 应用中,指定哈希以允许加载所需的脚本。
- 指定
- style-src:指示样式表的有效源。
- 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - 如果应用使用嵌入式样式,则指定
unsafe-inline
以允许使用嵌入式样式。
- 指定
- upgrade-insecure-requests:指示应通过 HTTPS 安全地获取来自不安全 (HTTP) 源的内容 URL。
- base-uri:限制页面的
<base>
标记的 URL。 指定self
,以指示应用的来源(包括方案和端口号)是有效源。 - default-src:指示未被策略显式指定的源指令的回退。 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - img-src:指示图像的有效源。
- 指定
data:
,以允许从data:
URL 加载图像。 - 指定
https:
,以允许从 HTTPS 终结点加载图像。
- 指定
- object-src:指示
<object>
、<embed>
和<applet>
标记的有效源。 指定none
以阻止所有 URL 源。 - script-src:指示脚本的有效源。
- 指定用于启动脚本的
https://stackpath.bootstrapcdn.com/
主机源。 - 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - 在客户端 Blazor 应用中:
- 指定
unsafe-eval
以允许客户端 Blazor Mono 运行时正常运行。 - 指定任何其他哈希值以允许加载所需的非框架脚本。
- 指定
- 在服务器端 Blazor 应用中,指定哈希以允许加载所需的脚本。
- 指定用于启动脚本的
- style-src:指示样式表的有效源。
- 指定用于启动样式表的
https://stackpath.bootstrapcdn.com/
主机源。 - 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - 指定
unsafe-inline
,以允许使用内联样式。
- 指定用于启动样式表的
- upgrade-insecure-requests:指示应通过 HTTPS 安全地获取来自不安全 (HTTP) 源的内容 URL。
- base-uri:限制页面的
<base>
标记的 URL。 指定self
,以指示应用的来源(包括方案和端口号)是有效源。 - default-src:指示未被策略显式指定的源指令的回退。 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - img-src:指示图像的有效源。
- 指定
data:
,以允许从data:
URL 加载图像。 - 指定
https:
,以允许从 HTTPS 终结点加载图像。
- 指定
- object-src:指示
<object>
、<embed>
和<applet>
标记的有效源。 指定none
以阻止所有 URL 源。 - script-src:指示脚本的有效源。
- 指定用于启动脚本的
https://stackpath.bootstrapcdn.com/
主机源。 - 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - 在客户端 Blazor 应用中:
- 执行哈希以允许加载所需的脚本。
- 指定
unsafe-eval
,以使用eval()
以及通过字符串创建代码的方法。
- 在服务器端 Blazor 应用中,指定哈希以允许加载所需的脚本。
- 指定用于启动脚本的
- style-src:指示样式表的有效源。
- 指定用于启动样式表的
https://stackpath.bootstrapcdn.com/
主机源。 - 指定
self
,以指示应用的来源(包括方案和端口号)是有效源。 - 指定
unsafe-inline
,以允许使用内联样式。 UI 需要内联声明,以便在初始请求后重新连接客户端和服务器。 在将来的版本中,可能会删除内联样式,以便不再需要unsafe-inline
。
- 指定用于启动样式表的
- upgrade-insecure-requests:指示应通过 HTTPS 安全地获取来自不安全 (HTTP) 源的内容 URL。
除 Microsoft Internet Explorer 外的所有浏览器都支持上述指令。
获取其他内联脚本的 SHA 哈希:
- 应用应用策略部分中所示的 CSP。
- 在本地运行应用时访问浏览器的开发人员工具控制台。 当存在 CSP 标头或
meta
标记时,浏览器将为遭到阻止的脚本计算和显示哈希。 - 将浏览器提供的哈希复制到
script-src
源。 在每个哈希两边使用单引号。
有关内容安全策略级别 2 浏览器的支持矩阵,请参阅我可以使用:内容安全策略级别 2。
应用策略
使用 <meta>
标记来应用策略:
- 将
http-equiv
属性的值设置为Content-Security-Policy
。 - 将指令置于
content
属性值中。 使用分号 (;
) 分隔指令。 - 始终将
meta
标记置于<head>
内容中。
以下各部分介绍示例策略。 对于 Blazor 的每个版本,本文都对这些示例进行了版本控制。 要使用适用于你的版本的版本,请在此网页上使用“版本”下拉选择器选择文档版本。
服务器端 Blazor 应用
在 <head>
内容中,应用“策略指令”部分中描述的指令:
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self';
style-src 'self';
upgrade-insecure-requests;">
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src https://stackpath.bootstrapcdn.com/
'self';
style-src https://stackpath.bootstrapcdn.com/
'self'
'unsafe-inline';
upgrade-insecure-requests;">
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src https://stackpath.bootstrapcdn.com/
'self'
'sha256-34WLX60Tw3aG6hylk0plKbZZFXCuepeQ6Hu7OqRf8PI=';
style-src https://stackpath.bootstrapcdn.com/
'self'
'unsafe-inline';
upgrade-insecure-requests;">
添加应用所需的其他 script-src
和 style-src
哈希。 在开发期间,使用联机工具或浏览器开发人员工具来计算哈希。 例如,以下浏览器工具控制台错误为策略未涵盖的必需脚本报告哈希:
拒绝执行内联脚本,因为它违反以下内容安全策略指令:“...”。 若要启用内联执行,需要使用“unsafe-inline”关键字、哈希(“sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=”)或 nonce(“nonce-...”)。
与错误关联的特定脚本显示在错误旁边的控制台中。
客户端 Blazor 应用
在 <head>
内容中,应用“策略指令”部分中描述的指令:
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self'
'wasm-unsafe-eval';
style-src 'self';
upgrade-insecure-requests;">
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self'
'unsafe-eval';
style-src 'self';
upgrade-insecure-requests;">
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self'
'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA='
'unsafe-eval';
style-src 'self';
upgrade-insecure-requests;">
注意
sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=
哈希表示用于客户端 Blazor 应用的内联脚本。 将来可能会将其删除。
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src https://stackpath.bootstrapcdn.com/
'self'
'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA='
'unsafe-eval';
style-src https://stackpath.bootstrapcdn.com/
'self'
'unsafe-inline';
upgrade-insecure-requests;">
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src https://stackpath.bootstrapcdn.com/
'self'
'sha256-v8ZC9OgMhcnEQ/Me77/R9TlJfzOBqrMTW8e1KuqLaqc='
'sha256-If//FtbPc03afjLezvWHnC3Nbu4fDM04IIzkPaf3pH0='
'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA='
'unsafe-eval';
style-src https://stackpath.bootstrapcdn.com/
'self'
'unsafe-inline';
upgrade-insecure-requests;">
添加应用所需的其他 script-src
和 style-src
哈希。 在开发期间,使用联机工具或浏览器开发人员工具来计算哈希。 例如,以下浏览器工具控制台错误为策略未涵盖的必需脚本报告哈希:
拒绝执行内联脚本,因为它违反以下内容安全策略指令:“...”。 若要启用内联执行,需要使用“unsafe-inline”关键字、哈希(“sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=”)或 nonce(“nonce-...”)。
与错误关联的特定脚本显示在错误旁边的控制台中。
在非 Development
环境中应用 CSP
将 CSP 应用于 Blazor 应用的 <head>
内容时,它会干扰 Development
环境中的本地测试。 例如,无法加载浏览器链接和浏览器刷新脚本。 以下示例演示如何在非 Development
环境中应用 CSP 的 <meta>
标记。
注意
本节中的示例不显示 CSP 的完整 <meta>
标记。 完整 <meta>
标记可以在本文前面的应用策略一节的小节中找到。
有三种常规方法可用:
- 通过
App
组件应用 CSP,该组件将 CSP 应用于应用的所有布局。 - 如果需要将 CSP 应用到应用的不同区域(例如,仅用于管理页面的自定义 CSP),请使用
<HeadContent>
标记按布局应用 CSP。 为了完全有效,每个应用布局文件都必须采用该方法。 - 托管服务或服务器可以通过添加应用的传出响应的
Content-Security-Policy
标头来提供 CSP。 由于该方法因托管服务或服务器而异,因此不在下面的示例中进行讨论。 如果想要采用该方法,请参阅托管服务提供程序或服务器的文档。
Blazor Web App 方法
在 App
组件 (Components/App.razor
) 中,注入 IHostEnvironment:
@inject IHostEnvironment Env
在 App
组件的 <head>
内容中,当不在 Development
环境中时应用 CSP:
@if (!Env.IsDevelopment())
{
<meta ...>
}
或者,在 Components/Layout
文件夹中按布局应用 CSP,如以下示例所示。 确保每个布局都指定一个 CSP。
@inject IHostEnvironment Env
@if (!Env.IsDevelopment())
{
<HeadContent>
<meta ...>
</HeadContent>
}
Blazor WebAssembly 应用方法
在 App
组件 (App.razor
) 中,注入 IWebAssemblyHostEnvironment:
@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IWebAssemblyHostEnvironment Env
在 App
组件的 <head>
内容中,当不在 Development
环境中时应用 CSP:
@if (!Env.IsDevelopment())
{
<HeadContent>
<meta ...>
</HeadContent>
}
或者,使用前面的代码,但在 Layout
文件夹中按布局应用 CSP。 确保每个布局都指定一个 CSP。
元标记限制
<meta>
标记策略不支持以下指令:
要支持上述指令,请使用名为 Content-Security-Policy
的标头。 指令字符串是标头的值。
测试策略并接收违规报告
测试有助于确认在生成初始策略时不会无意中阻止第三方脚本。
要在不强制实施策略指令的情况下在一段时间内测试策略,请将基于标头的策略的 <meta>
标记的 http-equiv
属性或标头名称设置为 Content-Security-Policy-Report-Only
。 将故障报告作为 JSON 文档发送到指定的 URL。 有关详细信息,请参阅 MDN Web 文档:Content-Security-Policy-Report-Only。
要在策略处于活动状态时报告违规,请参阅以下文章:
虽然不再建议使用 report-uri
,但在所有主要浏览器都支持 report-to
之前,都应使用这两个指令。 不要只使用 report-uri
,因为随时可能从浏览器中删除对 report-uri
的支持 。 完全支持 report-to
时,请删除策略中对 report-uri
的支持。 要跟踪 report-to
的使用情况,请参阅我可以使用:report-to。
每次发布时测试和更新应用的策略。
疑难解答
- 浏览器的开发人员工具控制台中出现错误。 浏览器提供以下信息:
- 不符合策略的元素。
- 如何修改策略以允许遭到阻止的项目。
- 仅当客户端的浏览器支持所有包含的指令时,策略才完全有效。 有关当前浏览器支持矩阵,请参阅我可以使用:Content-Security-Policy。