gudufy头像
关注

Blazor 安全设计:一个 Blazor Admin 后台需要防哪些攻击?

这篇是安全专题的总览,把散落在各篇里的机制汇总成一张"攻击面 → 防护 → 证据"的对照表。目标不是制造紧张感,而是让每一类风险都能指到具体代码。


一、先明确威胁模型

后台系统面对的主要是三类人:

攻击者手里有什么想干什么
未登录的外部人员只知道后台地址撞库、爆破、探测接口
已登录的低权限用户合法账号(比如普通员工)越权看/改不该碰的数据
内网中的其它系统网络可达性通过 SSRF 等入口横向移动

下面所有防护都对应这三类。


二、总览:攻击面 → 防护 → 证据

攻击面防护机制源码测试
会话伪造 / 篡改Data Protection 加密登录票据 + 统一 purposeAdminContext.Auth.cs、EasyAdminLoginTicketAuthenticationHandler.csAuthenticationTests
后台入口探测AdminRouteSecret(中间件 404 + 组件二次校验)AdminExtensions.cs、AdminContext.Auth.cs——
暴力破解登录失败锁定 + 验证码SecurityOptions.LoginFailureLimit / LoginLockout、EnableLoginCaptcha——
CSRFAntiforgery 过滤器(写方法校验)EasyAdminAntiforgeryFilter.csCsrfTests
路由越权AuthPath(路由 + 导航拦截)AdminContext.Authorization.cs——
操作越权AuthButton + AdminButtonAttributeAdminTable.razor、AdminButtonAttribute.csAuthorizationTests
数据越权(查询/改/删/导入)ApplyDataPermission + FilterAuthorizedAsyncFreeSqlExtensions.csDataPermissionTests
文件上传绕过扩展名白/黑名单 + Magic Number + ImageSharpFileSecurityValidator.cs、FileService.csFileSecurityValidatorTests、FileUploadSecurityTests
路径穿越SafePathService(拒绝 ../盘符/UNC)SafePathService.csPathTraversalTests
SSRF协议白名单 + 逐跳校验 + 连接前锁定 IPRemoteContentDownloader.cs、FileSecurityValidator.csSsrfTests
越权订阅推送Hub 不接受客户端 userIdNotificationHub.csNotificationHubTests
越权改消息状态只取 Id + 当前用户条件AdminMessageService.csMessageReadTests
密码泄露PBKDF2 + Salt + 固定时间比较PBKDF2Encrypt.csPbkdf2UpgradeTests
匿名接口滥用限流 + 参数校验 + 不泄露异常WeChatAppController.cs 等AuthorizationTests
多租户串数据独立库 + 文件目录 + 缓存/锁前缀MultiTenantService.cs、AdminContext.Tenant.csTenantIsolationTests、TenantCacheIsolationTests
异常信息泄露通用提示 + TraceIdApprovalService.GenericFailureApprovalConcurrencyTests

三、逐项展开

1. 会话:票据是加密的,且不能跨用途复用

登录成功后写的是加密票据,内容是 userId|loginTime:

var encryptedData = _loginTicketProtector.Protect($"{user.Id}|{user.LoginTime.ToString(LoginTimeFormat, CultureInfo.InvariantCulture)}");

_loginTicketProtector 来自 IDataProtectionProvider.CreateProtector("EasyAdminBlazor.LoginTicket.v1")。测试锁定了两条:

[Fact] public void LoginTicket_InvalidPurpose_CannotBeUnprotected()   // 换个 purpose 解不开
[Fact] public void EphemeralDataProtector_RoundTripsLoginTicket()

还有一条跨文件一致性断言,防止以后有人改了 purpose 导致 Hub 认证失效:

[Theory]
[InlineData("EasyAdminBlazor/Hubs/NotificationHub.cs")]
[InlineData("Extensions/EasyAdminBlazor.Chat/ChatHub.cs")]
[InlineData("EasyAdminBlazor/AdminContext.cs")]
[InlineData("EasyAdminBlazor/Components/Layout/Widget.razor")]
public void LoginTicketProtectorPurpose_IsConsistent(string relativePath)
{
    var source = ReadSource(relativePath);
    source.Should().Contain("EasyAdminBlazor.LoginTicket.v1");
}

2. CSRF:只拦写方法,失败返回 400

[Theory]
[InlineData("GET")] [InlineData("HEAD")] [InlineData("OPTIONS")] [InlineData("TRACE")]
public async Task SafeHttpMethods_AreNotValidated(string method)   // 安全方法放行

[Theory]
[InlineData("POST")] [InlineData("PUT")] [InlineData("PATCH")] [InlineData("DELETE")]
public async Task WriteHttpMethods_AreValidated(string method)     // 写方法必须校验

[Fact]
public async Task PostWithoutToken_IsRejectedWith400()             // 失败是 400,不是 500

三条约束都很关键:

  • 只拦写方法:如果连 GET 都要求令牌,缓存和预取会出问题;
  • 失败返回 400 而不是 500:令牌无效是客户端问题,不该记成服务端错误;
  • AntiforgeryDisabled 时可整体关闭(默认开启,SecurityOptions.AntiforgeryEnabled = true)。

3. 授权:四个层次缺一不可

这一块第 08、09、24 篇讲透了,这里只列结论:

路由级  AuthPath            能不能进页面
操作级  AuthButton          能不能点按钮
方法级  AdminButtonAttribute 方法能不能执行
数据级  FilterAuthorizedAsync 能操作哪些行

4. 文件与路径:两套独立的校验

内容防伪(第 23 篇):

if (FileSignatures.TryGetValue(extension, out var signatures))
{
    return await HasAnyPrefixAsync(input, signatures, cancellationToken);
}

return false;   // 未知扩展名 fail-closed

路径防穿越(SafePathService):

private readonly SafePathService _service = SafePathService.Instance;

[Theory]
[InlineData("..")]
[InlineData("../../etc/passwd")]
[InlineData("a/../../b")]
[InlineData("..\\..\\windows\\system32")]
[InlineData("C:/windows/system32")]
[InlineData("//server/share/file")]
public void NormalizeRelative_TraversalAttempts_Throw(string input)
{
    var act = () => _service.NormalizeRelative(input, allowRoot: false);
    act.Should().Throw<UnauthorizedAccessException>();
}

还有一个容易漏掉的用例:

[Fact]
public void IsContained_SiblingDirectoryWithSamePrefix_ReturnsFalse()
{
    var root = Path.Combine(Path.GetTempPath(), "eab-root");
    // eab-root-evil 以 eab-root 为前缀,但不是子目录
    var sibling = Path.Combine(Path.GetTempPath(), "eab-root-evil", "file.txt");
    _service.IsContained(root, sibling).Should().BeFalse();
}

如果只用 StartsWith(root) 判断包含关系,eab-root-evil 就能绕过。 这是路径校验的经典坑。

5. SSRF:出站请求也要校验目标

第 11 篇讲透了七层防护。核心两条:

  • 每跳重定向都重新校验(禁止自动重定向);
  • ConnectCallback 在建立 TCP 连接前再次校验实际 IP,关闭 DNS Rebinding 的 TOCTOU 窗口。

6. 多租户:数据库隔离 ≠ 系统隔离

第 13、15 篇讲过:数据库、文件目录、缓存键、分布式锁都要带租户维度。测试里有一组专门的候选键清单:

"tenant:main:SysConfig:",
"tenant:main:UserRoles:",
"tenant:main:Dict:",
"tenant:main:chat_messages:",
"tenant:main:save_messages_lock",

7. 信息泄露:错误信息要"对外模糊、对内精确"

private string GenericFailure(Exception ex)
{
    var traceId = Guid.NewGuid().ToString("N")[..16];
    _logger.LogError(ex, "审批处理失败,TraceId:{TraceId}", traceId);
    return LF("审批处理失败,请稍后重试。TraceId:{0}", traceId);
}

用户拿到的是通用提示 + TraceId;数据库异常、表名、SQL 片段只进日志。AuthorizationTests 里还有一条约束:控制器源码里不得出现 ex.Message。

DatabaseLogger 落库时也做了截断(消息 2000 / 异常 12000),并且写日志失败不会影响业务(第 27 篇)。


四、框架已做 vs 需要自己补

项目框架已做需要你补
密码哈希PBKDF2 + 平滑升级密码强度策略、历史密码限制
登录防护失败锁定、验证码二次验证(2FA)、异地登录提醒
授权路由/按钮/方法/数据四层权限矩阵的正确配置与验收
文件类型/内容/路径/大小病毒扫描、CDR、独立域名下发
SSRF出站请求完整防护代理环境下的额外确认
CSRF写方法令牌校验自定义接口注册到 MVC 过滤器链
多租户库/文件/缓存/锁隔离跨租户统计的权限控制
审计操作日志 + 登录日志 + 错误日志日志保留期限、归档与合规要求
传输——HTTPS、证书、HSTS
运维——备份、WAF/限流、端口暴露面、最小权限账号

这张表的右列不是框架的缺陷,而是产品与运维决策。 比如"是否要求 2FA"取决于客户合规要求,框架不该替业务决定。


五、上线安全清单

结合 SecurityOptions 和部署文档(第 28 篇),上线前逐条确认:

项默认值上线动作
AdminRouteSecreti4ByMAX4换成自定义值
AesKey示例值换成长随机串
默认管理员密码123yyq首次登录强制改密,确认流程可用
MaxUploadSize10MB按业务调整,不要无限放大
MaxRemoteRedirects3一般不用改
LoginFailureLimit / LoginLockout5 次 / 15 分钟按业务调整
AntiforgeryEnabledtrue不要关
RateLimitEnabledtrue确认匿名接口都有限流
ExternalApiTimeout10 秒按外部服务调整
UseAutoSyncStructure开发 true生产关闭
HTTPS——必须启用
wwwroot/uploads 权限——应用账号可写,不可执行
Redis——设密码、不暴露公网端口

六、小结

后台安全可以拆成六句话:

  1. 身份:票据加密、不能跨用途复用、多端登录可踢。
  2. 入口:路由安全码混淆探测成本,但真正的边界是登录与授权。
  3. 请求:写操作校验 CSRF,匿名接口限流 + 校验参数。
  4. 授权:路由、操作、方法、数据四层,前端隐藏只是体验。
  5. 内容:上传看内容不看声明,出站请求校验目标,路径拒绝上跳。
  6. 信息:对外模糊(通用提示 + TraceId),对内精确(日志含租户/用户/路径)。

这些机制在仓库里都有对应源码和测试;真正需要你判断的是:权限矩阵怎么配、上线参数怎么改、业务上还有哪些特殊约束。


如果你正在用 .NET 10 + Blazor 做企业后台,可以按这篇的对照表检查自己的项目。EasyAdminBlazor 的安全组件与测试都在仓库里,能直接复用,也能作为自研时的参考清单。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/gudufy/article/details/167072442

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--