作为资深开发者,我深知安全偷懒的代价——凌晨被生产环境漏洞警报惊醒、用户数据泄露或收到勒索邮件。本文将用真实案例和久经考验的策略,手把手教你加固 .NET 9 应用。
在动手实施前,先了解主要威胁:
仅靠密码很脆弱,多因素认证(MFA) 能提供额外保护层:
services.AddIdentity<ApplicationUser, IdentityRole>(options => {
options.Password.RequireDigit = true; // 强制包含数字
options.Password.RequiredLength = 8; // 最小长度8位
options.Password.RequireNonAlphanumeric = true; // 必须含特殊字符
options.SignIn.RequireConfirmedEmail = true; // 需验证邮箱
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
建议集成 TOTP(基于时间的一次性密码),如 Google Authenticator。
避免硬编码角色检查,改用策略控制权限:
services.AddAuthorization(options => {
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin")); // 仅管理员
options.AddPolicy("CanEditContent", policy => policy.RequireClaim("Permission", "Edit")); // 需编辑权限
});
控制器中应用策略:
[Authorize(Policy = "AdminOnly")]
public IActionResult AdminDashboard() {
return View();
}
永远不要拼接用户输入到 SQL 语句! 使用参数化查询或 Entity Framework 等 ORM 工具。
❌ 错误示例:
var query = $"SELECT * FROM Users WHERE Username = '{username}'";
✅ 正确做法:
var user = dbContext.Users.FirstOrDefault(u => u.Username == username);
若需原生 SQL,使用参数化:
var users = dbContext.Users.FromSqlRaw("SELECT * FROM Users WHERE Username = @p0", username).ToList();
确保 JWT 正确签名并拒绝过期令牌:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.RequireHttpsMetadata = true; // 强制 HTTPS
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters {
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])), // 签名密钥
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true, // 验证有效期
};
});
防御暴力破解和 API 滥用:
services.AddRateLimiter(options => {
options.AddPolicy("default", policy => policy.WithLimit(100, TimeSpan.FromMinutes(1))); // 每分钟最多100次请求
});
禁止内联脚本并限制资源来源:
app.Use(async (context, next) => {
context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; script-src 'self'"); // 仅允许同源脚本
await next();
});
表单提交必须包含防伪令牌:
[ValidateAntiForgeryToken]
public IActionResult SubmitForm(Model model) {
// 处理表单
}
永远不要硬编码密钥! 使用 Azure Key Vault、AWS Secrets Manager 或环境变量:
var secret = Configuration["SecretKey"]; // 从安全配置读取
.NET 9 内置加密工具:
var key = Convert.FromBase64String(Configuration["EncryptionKey"]); // 从配置获取密钥
using var aes = Aes.Create();
aes.Key = key;
aes.GenerateIV(); // 生成初始化向量
Log.Logger = new LoggerConfiguration()
.WriteTo.Console() // 输出到控制台
.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day) // 按天滚动日志
.CreateLogger();
记录登录失败和权限变更:
_logger.LogWarning("Failed login attempt for user {Username}", username); // 结构化日志
dotnet list package --outdated
dotnet security audit
等工具安全不是加个库就完事了,而是需要警惕心、最佳实践和持续学习的系统工程。在 .NET 9 应用中实施这些策略后,你保护的不仅是代码,更是用户、数据和声誉。
作为资深开发者,我亲眼见证过安全加固如何避免灾难。请严肃对待安全,持续改进!