一、 从“家门”开始:身份认证与授权

想象一下你的应用是一栋房子,身份认证就是确认访客是谁(查身份证),授权就是决定他能进哪个房间(给钥匙)。在 .NET Core 里,这套安保系统已经做得相当完善了。

最常用的方式是使用基于 Cookie 或 JWT(JSON Web Token)的认证。JWT 像一个数字通行证,服务器签发后,客户端在后续请求中带着它,服务器验证其真伪和有效性即可。

技术栈:ASP.NET Core 6.0 + JWT Bearer 认证

// Program.cs 或 Startup.cs 中的配置示例
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// 1. 配置JWT认证服务
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    // 从配置中读取密钥(切记不要硬编码在代码里!)
    var key = Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]);
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true, // 验证签发者
        ValidIssuer = builder.Configuration["Jwt:Issuer"], // 合法的签发者
        ValidateAudience = true, // 验证接收者
        ValidAudience = builder.Configuration["Jwt:Audience"], // 合法的接收者
        ValidateLifetime = true, // 验证令牌有效期
        ClockSkew = TimeSpan.Zero, // 容忍的时间偏移,设为0更严格
        IssuerSigningKey = new SymmetricSecurityKey(key) // 用于验证签名的密钥
    };
});

// 2. 配置授权策略(例如,要求用户拥有“Admin”角色)
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAdminRole", policy =>
        policy.RequireRole("Admin"));
});

var app = builder.Build();

app.UseAuthentication(); // 启用认证中间件
app.UseAuthorization();  // 启用授权中间件

// 3. 在控制器或Minimal API中使用
app.MapGet("/api/admin/data", () => "这是管理员数据")
    .RequireAuthorization("RequireAdminRole"); // 应用授权策略

app.Run();

注意事项:JWT 的密钥 (SecretKey) 必须足够复杂且妥善保管,最好使用配置中心或环境变量,绝不能提交到代码仓库。ClockSkew 设置为零可以防止利用时间差进行的攻击,但要求服务器间时间严格同步。

二、 给“输入”加上过滤网:防范注入与跨站脚本(XSS)

用户输入是最不可信的数据源。攻击者常常通过表单、URL参数、HTTP头等地方注入恶意代码。

1. SQL注入防护:永远不要拼接SQL字符串!使用参数化查询或ORM(如Entity Framework Core)是铁律。

技术栈:ASP.NET Core 6.0 + Entity Framework Core

// 错误示范:拼接字符串,极度危险!
// var sql = $"SELECT * FROM Users WHERE Name = '{userInput}' AND Password = '{passwordInput}'";

// 正确示范:使用EF Core的参数化查询
using Microsoft.EntityFrameworkCore;

public class UserService
{
    private readonly MyDbContext _context;

    public UserService(MyDbContext context)
    {
        _context = context;
    }

    public async Task<User> GetUserSafelyAsync(string userName)
    {
        // 使用FromSqlInterpolated或直接使用LINQ
        // EF Core会将这里的`userName`自动转换为参数,防止注入
        var user = await _context.Users
            .FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {userName}")
            .FirstOrDefaultAsync();

        // 更推荐的方式:使用LINQ,它是完全类型安全的
        // var user = await _context.Users.Where(u => u.Name == userName).FirstOrDefaultAsync();
        return user;
    }
}

2. 跨站脚本(XSS)防护:XSS攻击是让恶意脚本在受害者的浏览器中执行。.NET Core 提供了自动的编码防护。

  • Razor Pages / MVC 视图:默认输出时已经进行了HTML编码 (@Model.UserInput)。
  • API 返回纯文本或JSON:确保前端(如Vue/React)在渲染数据时使用安全的文本绑定(如 {{ }}textContent),而非 v-html / dangerouslySetInnerHTML。如果必须输出HTML,务必使用白名单库(如 HtmlSanitizer)进行清洗。
  • 设置HTTP安全头:在中间件中增加 X-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=block 可以提供额外的浏览器端防护。

三、 守护“数据”的隐私与完整性:敏感信息处理

1. 配置信息管理:连接字符串、API密钥、JWT密钥等敏感信息,绝不能写在 appsettings.json 里并提交到Git。应使用环境变量、Azure Key Vault、HashiCorp Vault 等安全存储,并通过 Configuration 系统读取。

// 从环境变量读取,优先级高于appsettings.json
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

// 或者使用UserSecrets进行本地开发(也不提交到Git)
// dotnet user-secrets set "DbPassword" "your_password"
var password = builder.Configuration["DbPassword"];

2. 数据加密

  • 传输中:强制使用 HTTPS(TLS)。在 StartupProgram 中可以使用 app.UseHttpsRedirection()
  • 存储中:对于密码,使用强哈希算法(如 PBKDF2, bcrypt, Argon2)加盐存储,切勿使用MD5、SHA1。.NET Core 提供了 PasswordHasher 工具。
using Microsoft.AspNetCore.Identity;

public class SecurityHelper
{
    // 使用ASP.NET Core Identity的密码哈希器
    private readonly PasswordHasher<object> _hasher = new PasswordHasher<object>();

    public string HashPassword(string password)
    {
        // 该方法会自动生成并包含盐值
        return _hasher.HashPassword(null, password);
    }

    public bool VerifyPassword(string hashedPassword, string providedPassword)
    {
        // 验证密码,结果会是 Success, Failed 或 NeedsRehash(当算法迭代次数升级时)
        var result = _hasher.VerifyHashedPassword(null, hashedPassword, providedPassword);
        return result == PasswordVerificationResult.Success;
    }
}

四、 提升“围墙”的高度:其他关键安全措施

1. 跨站请求伪造(CSRF)防护:对于使用Cookie认证的MVC/Razor Pages应用,ASP.NET Core 内置了防伪令牌(Antiforgery Token)验证,通过 [ValidateAntiForgeryToken] 特性即可启用。对于纯API(如Vue+WebAPI架构),由于通常使用JWT等存储在客户端(如localStorage)而非Cookie中的令牌,标准的CSRF攻击无效,但仍需注意确保API没有 unintended 的Cookie认证端点。

2. 适当的CORS策略:如果您的API需要被不同源的Web前端调用,必须配置CORS(跨源资源共享)。但策略要尽可能严格。

// 在Program.cs中配置一个命名策略
builder.Services.AddCors(options =>
{
    options.AddPolicy("MyAllowSpecificOrigins", policy =>
    {
        policy.WithOrigins("https://trusted-site.com", "https://another-trusted.site") // 只允许特定来源
              .AllowAnyHeader() // 允许任何头(根据需求可收紧,如 .WithHeaders)
              .AllowAnyMethod(); // 允许任何方法(根据需求可收紧,如 .WithMethods)
        // 注意:.AllowCredentials() 与 WithOrigins("*") 不能同时使用
    });
});

app.UseCors("MyAllowSpecificOrigins"); // 应用CORS中间件

3. 依赖包安全(Software Composition Analysis, SCA):使用 NuGet 管理的第三方包可能包含漏洞。应定期使用 dotnet list package --vulnerable 命令或集成工具(如 GitHub Dependabot, Snyk, WhiteSource)扫描项目,并及时升级到安全版本。

4. 日志与监控:记录重要的安全事件(如登录失败、越权访问尝试),但切记不要在日志中记录密码、信用卡号等敏感信息。使用结构化日志库(如Serilog)并配置安全的输出目标。

五、 实战场景与总结思考

应用场景:本文指南适用于所有基于 .NET Core 开发的 Web API、MVC 应用、Razor Pages 应用以及微服务。无论是企业级后台管理系统、电子商务平台还是面向公众的移动应用后端,都需要贯彻这些安全实践。

技术优缺点

  • 优点:.NET Core 框架本身提供了强大的、可扩展的安全基础设施(如认证/授权中间件、数据保护API、防伪令牌),使得实现常见安全功能事半功倍。其强类型和成熟的ORM(EF Core)也在很大程度上杜绝了注入类漏洞。
  • 挑战:安全配置选项繁多,理解不当可能导致错误配置,反而引入风险(如过于宽松的CORS)。开发者需要持续学习,跟上框架和安全威胁的更新。

注意事项

  1. 安全是持续过程:没有一劳永逸的解决方案。代码审计、渗透测试、依赖更新需要定期进行。
  2. 遵循最小权限原则:数据库连接账户、服务器进程运行账户只应拥有完成其功能所必需的最小权限。
  3. 不要自己发明加密算法:始终使用经过行业严格验证的库和算法。
  4. 错误处理要得体:向用户返回通用的错误信息(如“用户名或密码错误”),避免泄露系统细节(如“用户admin不存在”),以防被攻击者利用进行信息枚举。

文章总结: 加固 .NET Core 应用安全,就像为你的数字资产构建一座坚固的城堡。我们需要从身份认证与授权(城门守卫)入手,严格过滤所有用户输入(检查行李),精心保护敏感数据(藏好宝藏),并不断加固整体防线(提升城墙、巡逻监控)。框架提供了优秀的砖石和蓝图,但最终城堡的坚固程度,取决于开发者——也就是你——对安全原则的理解和一丝不苟的实践。记住,安全意识是每一位开发者最重要的“内置特性”,请务必时刻开启。