在Blazor中重新审视内容安全策略(CSP)随机数的使用

本文详细探讨了在Blazor和ASP.NET Core应用程序中实现强大的内容安全策略(CSP)的方法,重点介绍了CSP随机数的使用、支持的Blazor应用类型、安全头配置以及Visual Studio调试注意事项。

在Blazor中重新审视内容安全策略(CSP)随机数的使用

这篇博客探讨了在使用Blazor和ASP.NET Core实现的Web应用程序中实施强大的内容安全策略(CSP)。在实施CSP时,我始终推荐使用CSP随机数或至少使用CSP哈希。如果一个技术栈不支持CSP随机数,在实施安全且专业的Web应用程序时,您可能应该避免使用该解决方案。

代码:https://github.com/damienbod/BlazorServerOidc

较早的相关博客

Blazor应用程序类型

在Blazor中实施强大的内容安全策略(CSP)之前,必须确定您正在使用的特定Blazor应用程序类型。Blazor提供了各种形式和渲染模式,因此选择最适合您需求的模式至关重要。

  • Blazor Web Server (交互式服务器)
  • Blazor Web WASM (交互式WebAssembly)
  • Blazor Web 混合模式 (交互式自动)
  • 在ASP.NET Core中托管的Blazor WASM (Razor页面主机)
  • Blazor WASM 独立应用
  • Blazor Server,可以更新为Blazor Web Server (交互式服务器)

我只使用支持CSP随机数的Blazor应用程序类型和渲染模式。目前,只有三种类型的Blazor应用程序提供此支持:

  • Blazor Web Server (交互式服务器)
  • Blazor Web WASM (交互式WebAssembly)
  • Blazor Web 混合模式 (交互式自动)
  • 在ASP.NET Core中托管的Blazor WASM (Razor页面主机)
  • Blazor WASM 独立应用
  • Blazor Server,可以更新为Blazor Web Server (交互式服务器)

Blazor Web设置

当使用最新版本的Blazor时,如果应用程序中安全性很重要,可以使用交互式服务器渲染模式,并且应该避免使用交互式自动渲染模式。可以使用NetEscapades.AspNetCore.SecurityHeaders Nuget包进行设置,如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        
        // 添加服务到容器
        builder.Services.AddRazorComponents()
            .AddInteractiveServerComponents();
        
        builder.Services.AddHttpContextAccessor();
        
        // ...
        
        builder.Services.AddSecurityHeaderPolicies()
            .SetDefaultPolicy(SecurityHeadersDefinitions
            .GetHeaderPolicyCollection(oidcConfig["Authority"],
                builder.Environment.IsDevelopment()));
        
        var app = builder.Build();
        
        // ...
        
        app.UseSecurityHeaders();
        app.UseHttpsRedirection();
        app.UseAntiforgery();
        app.UseAuthentication();
        app.UseAuthorization();
        
        app.MapStaticAssets();
        app.MapRazorComponents<App>()
            .AddInteractiveServerRenderMode();
        
        app.MapLoginLogoutEndpoints();
        
        app.Run();
    }
}

实施安全头

NetEscapades.AspNetCore.SecurityHeaders Nuget包可用于在ASP.NET Core应用程序中实施安全头。这将安全头应用于不同端点的响应。其中一个头是浏览器CSP头。CSP随机数按照最新浏览器的推荐使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
namespace BlazorWebApp;

using Microsoft.AspNetCore.Builder;

public static class SecurityHeadersDefinitions
{
    public static HeaderPolicyCollection GetHeaderPolicyCollection(string? idpHost, bool isDev)
    {
        ArgumentNullException.ThrowIfNull(idpHost);
        
        var policy = new HeaderPolicyCollection()
            .AddFrameOptionsDeny()
            .AddContentTypeOptionsNoSniff()
            .AddReferrerPolicyStrictOriginWhenCrossOrigin()
            .AddCrossOriginOpenerPolicy(builder => builder.SameOrigin())
            .AddCrossOriginResourcePolicy(builder => builder.SameOrigin())
            // #if !DEBUG // 如果使用Visual Studio开发热重载,请移除
            .AddCrossOriginEmbedderPolicy(builder => builder.RequireCorp())
            // #endif
            .AddContentSecurityPolicy(builder =>
            {
                builder.AddObjectSrc().None();
                builder.AddBlockAllMixedContent();
                builder.AddImgSrc().Self().From("data:");
                builder.AddFormAction().Self().From(idpHost);
                builder.AddFontSrc().Self();
                builder.AddStyleSrc().Self().UnsafeInline();
                builder.AddBaseUri().Self();
                builder.AddFrameAncestors().None();
                
                // #if !DEBUG // 为Visual Studio开发移除
                builder.AddScriptSrc().WithNonce().UnsafeInline();
                // #endif
            })
            .RemoveServerHeader()
            .AddPermissionsPolicyWithDefaultSecureDirectives();
        
        if (!isDev)
        {
            // maxage = 一年秒数
            policy.AddStrictTransportSecurityMaxAgeIncludeSubDomains();
        }
        
        return policy;
    }
}

可以将头添加到服务中。

1
2
builder.Services.AddSecurityHeaderPolicies().SetDefaultPolicy(SecurityHeadersDefinitions.GetHeaderPolicyCollection(oidcConfig["Authority"],
    builder.Environment.IsDevelopment()));

HttpContextAccessor可用于从HTTP上下文中获取头,并用于在UI组件中加载脚本和样式。ImportMap使用随机数进行扩展。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" nonce="@Nonce" />
    <link rel="stylesheet" href="@Assets["app.css"]" nonce="@Nonce" />
    <link rel="stylesheet" href="@Assets["BlazorWebApp.styles.css"]" nonce="@Nonce" />
         
    <ImportMap AdditionalAttributes="@(new Dictionary<string, object>() { { "nonce", Nonce ?? "" }})" />
     
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet />
</head>
 
<body>
    <Routes @rendermode="InteractiveServer" />
    <script src="_framework/blazor.web.js" nonce="@Nonce"></script>
</body>
</html>

@code{
    public string? Nonce => HttpContextAccessor?.HttpContext?.GetNonce();
    [Inject] private IHttpContextAccessor? HttpContextAccessor { get; set; }
}

Visual Studio调试

当使用Visual Studio进行调试时,它会添加两个默认被阻止且应该被阻止的脚本。这是一种脚本攻击,在任何部署中都应被阻止。

如果您希望在Visual Studio调试中允许此操作,可以在SecurityHeadersDefinitions类中使用#if !DEBUG来允许以下注入的脚本:

1
2
3
4
<!-- Visual Studio Browser Link -->
<script type="text/javascript" src="/_vs/browserLink" async="async" id="__browserLink_initializationData" data-requestId="59852cf479154d149a3db2064a0722e6" data-requestMappingFromServer="false" data-connectUrl="http://localhost:63449/fd8b98433c6f43259bb7df9563900638/browserLink"></script>
<!-- End Browser Link -->
<script src="/_framework/aspnetcore-browser-refresh.js"></script>

注意事项

使用CSP随机数可以轻松地应用、更新和维护应用程序,并在所有环境中使用强大的CSP。我在开发、测试和生产设置中都使用这种方法。在构建专业的Web应用程序时,可能应该避免任何不支持CSP随机数的Web技术栈。Blazor InteractiveServer渲染模式有一个很好的解决方案。

链接

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计