dotnet-security

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

.NET Security - Quick Reference

.NET安全 - 快速参考

When NOT to Use This Skill

何时不使用本技能

  • General OWASP concepts - Use
    owasp
    or
    owasp-top-10
    skill
  • Java security - Use
    java-security
    skill
  • Python security - Use
    python-security
    skill
  • Secrets management - Use
    secrets-management
    skill
Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
dotnet
for ASP.NET Core security documentation.
  • 通用OWASP概念 - 使用
    owasp
    owasp-top-10
    技能
  • Java安全 - 使用
    java-security
    技能
  • Python安全 - 使用
    python-security
    技能
  • 密钥管理 - 使用
    secrets-management
    技能
深度知识:如需ASP.NET Core安全文档,请使用
mcp__documentation__fetch_docs
工具,指定技术类型为
dotnet

Dependency Auditing

依赖项审计

bash
undefined
bash
undefined

.NET built-in audit

.NET内置审计

dotnet list package --vulnerable
dotnet list package --vulnerable

Detailed audit with transitive dependencies

包含传递依赖项的详细审计

dotnet list package --vulnerable --include-transitive
dotnet list package --vulnerable --include-transitive

Check outdated packages

检查过时包

dotnet list package --outdated
dotnet list package --outdated

Snyk for .NET

使用Snyk进行.NET审计

snyk test
undefined
snyk test
undefined

CI/CD Integration

CI/CD集成

yaml
undefined
yaml
undefined

GitHub Actions

GitHub Actions

  • name: Security audit run: | dotnet list package --vulnerable --include-transitive dotnet tool install -g snyk snyk test
undefined
  • name: Security audit run: | dotnet list package --vulnerable --include-transitive dotnet tool install -g snyk snyk test
undefined

NuGet.config Security

NuGet.config安全配置

xml
<configuration>
  <packageSources>
    <!-- Use only trusted sources -->
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <!-- Use environment variables for private feeds -->
  </packageSourceCredentials>
</configuration>
xml
<configuration>
  <packageSources>
    <!-- 仅使用可信源 -->
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <!-- 对私有源使用环境变量 -->
  </packageSourceCredentials>
</configuration>

ASP.NET Core Security Configuration

ASP.NET Core安全配置

Program.cs Security Setup

Program.cs安全设置

csharp
var builder = WebApplication.CreateBuilder(args);

// Security headers
builder.Services.AddHsts(options =>
{
    options.MaxAge = TimeSpan.FromDays(365);
    options.IncludeSubDomains = true;
    options.Preload = true;
});

// CORS configuration
builder.Services.AddCors(options =>
{
    options.AddPolicy("Production", policy =>
    {
        policy.WithOrigins("https://myapp.com")
              .AllowCredentials()
              .WithMethods("GET", "POST", "PUT", "DELETE")
              .WithHeaders("Authorization", "Content-Type");
    });
});

// Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
        };
    });

// Rate limiting (.NET 7+)
builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("login", limiter =>
    {
        limiter.Window = TimeSpan.FromMinutes(15);
        limiter.PermitLimit = 5;
        limiter.QueueLimit = 0;
    });
});

var app = builder.Build();

// Security middleware order matters
app.UseHsts();
app.UseHttpsRedirection();
app.UseCors("Production");
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();
csharp
var builder = WebApplication.CreateBuilder(args);

// 安全标头
builder.Services.AddHsts(options =>
{
    options.MaxAge = TimeSpan.FromDays(365);
    options.IncludeSubDomains = true;
    options.Preload = true;
});

// CORS配置
builder.Services.AddCors(options =>
{
    options.AddPolicy("Production", policy =>
    {
        policy.WithOrigins("https://myapp.com")
              .AllowCredentials()
              .WithMethods("GET", "POST", "PUT", "DELETE")
              .WithHeaders("Authorization", "Content-Type");
    });
});

// 身份验证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
        };
    });

// 限流(.NET 7+)
builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("login", limiter =>
    {
        limiter.Window = TimeSpan.FromMinutes(15);
        limiter.PermitLimit = 5;
        limiter.QueueLimit = 0;
    });
});

var app = builder.Build();

// 安全中间件顺序很重要
app.UseHsts();
app.UseHttpsRedirection();
app.UseCors("Production");
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();

Security Headers Middleware

安全标头中间件

csharp
app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
    context.Response.Headers.Add("X-Frame-Options", "DENY");
    context.Response.Headers.Add("X-XSS-Protection", "0"); // Use CSP instead
    context.Response.Headers.Add("Referrer-Policy", "strict-origin-when-cross-origin");
    context.Response.Headers.Add("Content-Security-Policy",
        "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");

    await next();
});
csharp
app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
    context.Response.Headers.Add("X-Frame-Options", "DENY");
    context.Response.Headers.Add("X-XSS-Protection", "0"); // 建议使用CSP替代
    context.Response.Headers.Add("Referrer-Policy", "strict-origin-when-cross-origin");
    context.Response.Headers.Add("Content-Security-Policy",
        "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");

    await next();
});

SQL Injection Prevention

SQL注入防护

Entity Framework Core - Safe

Entity Framework Core - 安全写法

csharp
// SAFE - LINQ queries
var user = await context.Users
    .FirstOrDefaultAsync(u => u.Email == email);

// SAFE - Parameterized raw SQL
var users = await context.Users
    .FromSqlRaw("SELECT * FROM Users WHERE Email = {0}", email)
    .ToListAsync();

// SAFE - Interpolated (converted to parameters)
var users = await context.Users
    .FromSqlInterpolated($"SELECT * FROM Users WHERE Email = {email}")
    .ToListAsync();
csharp
// 安全 - LINQ查询
var user = await context.Users
    .FirstOrDefaultAsync(u => u.Email == email);

// 安全 - 参数化原生SQL
var users = await context.Users
    .FromSqlRaw("SELECT * FROM Users WHERE Email = {0}", email)
    .ToListAsync();

// 安全 - 插值语法(会转换为参数)
var users = await context.Users
    .FromSqlInterpolated($"SELECT * FROM Users WHERE Email = {email}")
    .ToListAsync();

Entity Framework Core - UNSAFE

Entity Framework Core - 不安全写法

csharp
// UNSAFE - String concatenation
var query = $"SELECT * FROM Users WHERE Email = '{email}'";  // NEVER!
var users = await context.Users.FromSqlRaw(query).ToListAsync();

// UNSAFE - FormattableString with raw
var users = await context.Users
    .FromSqlRaw($"SELECT * FROM Users WHERE Email = '{email}'")  // NEVER!
    .ToListAsync();
csharp
// 不安全 - 字符串拼接
var query = $"SELECT * FROM Users WHERE Email = '{email}'";  // 绝对禁止!
var users = await context.Users.FromSqlRaw(query).ToListAsync();

// 不安全 - 直接使用插值字符串的原生SQL
var users = await context.Users
    .FromSqlRaw($"SELECT * FROM Users WHERE Email = '{email}'")  // 绝对禁止!
    .ToListAsync();

Dapper - Safe

Dapper - 安全写法

csharp
// SAFE - Anonymous parameters
var user = await connection.QueryFirstOrDefaultAsync<User>(
    "SELECT * FROM Users WHERE Email = @Email",
    new { Email = email }
);

// SAFE - DynamicParameters
var parameters = new DynamicParameters();
parameters.Add("Email", email);
var user = await connection.QueryFirstOrDefaultAsync<User>(
    "SELECT * FROM Users WHERE Email = @Email",
    parameters
);
csharp
// 安全 - 匿名参数
var user = await connection.QueryFirstOrDefaultAsync<User>(
    "SELECT * FROM Users WHERE Email = @Email",
    new { Email = email }
);

// 安全 - DynamicParameters
var parameters = new DynamicParameters();
parameters.Add("Email", email);
var user = await connection.QueryFirstOrDefaultAsync<User>(
    "SELECT * FROM Users WHERE Email = @Email",
    parameters
);

XSS Prevention

XSS防护

Razor Pages (Auto-encoding)

Razor Pages(自动编码)

html
<!-- SAFE - Auto-encoded -->
<p>@Model.UserInput</p>

<!-- UNSAFE - Raw HTML -->
<p>@Html.Raw(Model.UserInput)</p>  <!-- Avoid if possible -->
html
<!-- 安全 - 自动编码 -->
<p>@Model.UserInput</p>

<!-- 不安全 - 原始HTML -->
<p>@Html.Raw(Model.UserInput)</p>  <!-- 尽可能避免使用 -->

Manual Sanitization

手动清理

csharp
using Ganss.Xss;

var sanitizer = new HtmlSanitizer();
sanitizer.AllowedTags.Add("p");
sanitizer.AllowedTags.Add("b");
sanitizer.AllowedTags.Add("i");

string safeHtml = sanitizer.Sanitize(userInput);
csharp
using Ganss.Xss;

var sanitizer = new HtmlSanitizer();
sanitizer.AllowedTags.Add("p");
sanitizer.AllowedTags.Add("b");
sanitizer.AllowedTags.Add("i");

string safeHtml = sanitizer.Sanitize(userInput);

API Response Encoding

API响应编码

csharp
using System.Text.Encodings.Web;

var encoder = HtmlEncoder.Default;
var safeString = encoder.Encode(userInput);
csharp
using System.Text.Encodings.Web;

var encoder = HtmlEncoder.Default;
var safeString = encoder.Encode(userInput);

Authentication & Authorization

身份验证与授权

JWT Token Generation

JWT令牌生成

csharp
public class JwtService
{
    private readonly IConfiguration _config;

    public JwtService(IConfiguration config) => _config = config;

    public string GenerateToken(User user)
    {
        var key = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Email, user.Email),
            new Claim(ClaimTypes.Role, user.Role)
        };

        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.UtcNow.AddHours(1),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}
csharp
public class JwtService
{
    private readonly IConfiguration _config;

    public JwtService(IConfiguration config) => _config = config;

    public string GenerateToken(User user)
    {
        var key = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Email, user.Email),
            new Claim(ClaimTypes.Role, user.Role)
        };

        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.UtcNow.AddHours(1),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

Password Hashing with Identity

使用Identity进行密码哈希

csharp
// Use ASP.NET Core Identity's PasswordHasher
var hasher = new PasswordHasher<User>();

// Hash password
string hashed = hasher.HashPassword(user, password);

// Verify password
var result = hasher.VerifyHashedPassword(user, hashed, password);
if (result == PasswordVerificationResult.Success)
{
    // Password matches
}
csharp
// 使用ASP.NET Core Identity的PasswordHasher
var hasher = new PasswordHasher<User>();

// 哈希密码
string hashed = hasher.HashPassword(user, password);

// 验证密码
var result = hasher.VerifyHashedPassword(user, hashed, password);
if (result == PasswordVerificationResult.Success)
{
    // 密码匹配
}

Authorization Policies

授权策略

csharp
// Program.cs
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy =>
        policy.RequireRole("Admin"));

    options.AddPolicy("ResourceOwner", policy =>
        policy.Requirements.Add(new ResourceOwnerRequirement()));
});

// Custom requirement handler
public class ResourceOwnerHandler : AuthorizationHandler<ResourceOwnerRequirement, Resource>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        ResourceOwnerRequirement requirement,
        Resource resource)
    {
        var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
        if (resource.OwnerId == userId)
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;
    }
}

// Controller usage
[Authorize(Policy = "AdminOnly")]
public IActionResult AdminDashboard() => View();
csharp
// Program.cs
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy =>
        policy.RequireRole("Admin"));

    options.AddPolicy("ResourceOwner", policy =>
        policy.Requirements.Add(new ResourceOwnerRequirement()));
});

// 自定义需求处理器
public class ResourceOwnerHandler : AuthorizationHandler<ResourceOwnerRequirement, Resource>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        ResourceOwnerRequirement requirement,
        Resource resource)
    {
        var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
        if (resource.OwnerId == userId)
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;
    }
}

// 控制器使用
[Authorize(Policy = "AdminOnly")]
public IActionResult AdminDashboard() => View();

Input Validation

输入验证

Data Annotations

数据注解

csharp
public class CreateUserRequest
{
    [Required]
    [EmailAddress]
    [StringLength(255)]
    public string Email { get; set; } = default!;

    [Required]
    [StringLength(128, MinimumLength = 12)]
    [RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).+$",
        ErrorMessage = "Password must contain uppercase, lowercase, number and special character")]
    public string Password { get; set; } = default!;

    [Required]
    [StringLength(100, MinimumLength = 2)]
    [RegularExpression(@"^[a-zA-Z\s\-']+$")]
    public string Name { get; set; } = default!;
}

[HttpPost]
public IActionResult CreateUser([FromBody] CreateUserRequest request)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    // request is validated
}
csharp
public class CreateUserRequest
{
    [Required]
    [EmailAddress]
    [StringLength(255)]
    public string Email { get; set; } = default!;

    [Required]
    [StringLength(128, MinimumLength = 12)]
    [RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).+$",
        ErrorMessage = "密码必须包含大写字母、小写字母、数字和特殊字符")]
    public string Password { get; set; } = default!;

    [Required]
    [StringLength(100, MinimumLength = 2)]
    [RegularExpression(@"^[a-zA-Z\s\-']+$")]
    public string Name { get; set; } = default!;
}

[HttpPost]
public IActionResult CreateUser([FromBody] CreateUserRequest request)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    // 请求已通过验证
}

FluentValidation

FluentValidation

csharp
public class CreateUserValidator : AbstractValidator<CreateUserRequest>
{
    public CreateUserValidator()
    {
        RuleFor(x => x.Email)
            .NotEmpty()
            .EmailAddress()
            .MaximumLength(255);

        RuleFor(x => x.Password)
            .NotEmpty()
            .MinimumLength(12)
            .MaximumLength(128)
            .Matches(@"[A-Z]").WithMessage("Must contain uppercase")
            .Matches(@"[a-z]").WithMessage("Must contain lowercase")
            .Matches(@"\d").WithMessage("Must contain digit")
            .Matches(@"[@$!%*?&]").WithMessage("Must contain special character");

        RuleFor(x => x.Name)
            .NotEmpty()
            .Length(2, 100)
            .Matches(@"^[a-zA-Z\s\-']+$");
    }
}
csharp
public class CreateUserValidator : AbstractValidator<CreateUserRequest>
{
    public CreateUserValidator()
    {
        RuleFor(x => x.Email)
            .NotEmpty()
            .EmailAddress()
            .MaximumLength(255);

        RuleFor(x => x.Password)
            .NotEmpty()
            .MinimumLength(12)
            .MaximumLength(128)
            .Matches(@"[A-Z]").WithMessage("必须包含大写字母")
            .Matches(@"[a-z]").WithMessage("必须包含小写字母")
            .Matches(@"\d").WithMessage("必须包含数字")
            .Matches(@"[@$!%*?&]").WithMessage("必须包含特殊字符");

        RuleFor(x => x.Name)
            .NotEmpty()
            .Length(2, 100)
            .Matches(@"^[a-zA-Z\s\-']+$");
    }
}

Secure File Upload

安全文件上传

csharp
[HttpPost("upload")]
[RequestSizeLimit(10 * 1024 * 1024)] // 10 MB
public async Task<IActionResult> Upload(IFormFile file)
{
    // Validate content type
    var allowedTypes = new[] { "image/jpeg", "image/png", "application/pdf" };
    if (!allowedTypes.Contains(file.ContentType))
        return BadRequest("File type not allowed");

    // Validate file extension
    var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".pdf" };
    var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
    if (!allowedExtensions.Contains(extension))
        return BadRequest("File extension not allowed");

    // Generate safe filename
    var safeName = $"{Guid.NewGuid()}{extension}";
    var uploadPath = Path.Combine(_uploadDirectory, safeName);

    // Save file
    await using var stream = new FileStream(uploadPath, FileMode.Create);
    await file.CopyToAsync(stream);

    return Ok(new { filename = safeName });
}
csharp
[HttpPost("upload")]
[RequestSizeLimit(10 * 1024 * 1024)] // 10 MB
public async Task<IActionResult> Upload(IFormFile file)
{
    // 验证内容类型
    var allowedTypes = new[] { "image/jpeg", "image/png", "application/pdf" };
    if (!allowedTypes.Contains(file.ContentType))
        return BadRequest("不允许的文件类型");

    // 验证文件扩展名
    var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".pdf" };
    var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
    if (!allowedExtensions.Contains(extension))
        return BadRequest("不允许的文件扩展名");

    // 生成安全文件名
    var safeName = $"{Guid.NewGuid()}{extension}";
    var uploadPath = Path.Combine(_uploadDirectory, safeName);

    // 保存文件
    await using var stream = new FileStream(uploadPath, FileMode.Create);
    await file.CopyToAsync(stream);

    return Ok(new { filename = safeName });
}

Secrets Management

密钥管理

User Secrets (Development)

用户密钥(开发环境)

bash
undefined
bash
undefined

Initialize user secrets

初始化用户密钥

dotnet user-secrets init
dotnet user-secrets init

Set secrets

设置密钥

dotnet user-secrets set "Jwt:Key" "your-secret-key" dotnet user-secrets set "ConnectionStrings:Default" "your-connection-string"
undefined
dotnet user-secrets set "Jwt:Key" "your-secret-key" dotnet user-secrets set "ConnectionStrings:Default" "your-connection-string"
undefined

appsettings.json (DO NOT store secrets)

appsettings.json(请勿存储密钥)

json
{
  "Jwt": {
    "Issuer": "https://myapp.com",
    "Audience": "https://myapp.com"
    // Key should come from environment or secrets manager
  }
}
json
{
  "Jwt": {
    "Issuer": "https://myapp.com",
    "Audience": "https://myapp.com"
    // 密钥应来自环境变量或密钥管理器
  }
}

Environment Variables

环境变量

csharp
// Program.cs - Load from environment
builder.Configuration.AddEnvironmentVariables();

// Access
var jwtKey = builder.Configuration["Jwt:Key"]
    ?? throw new InvalidOperationException("JWT Key not configured");
csharp
// Program.cs - 从环境变量加载
builder.Configuration.AddEnvironmentVariables();

// 访问
var jwtKey = builder.Configuration["Jwt:Key"]
    ?? throw new InvalidOperationException("未配置JWT密钥");

Azure Key Vault Integration

Azure Key Vault集成

csharp
builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{vaultName}.vault.azure.net/"),
    new DefaultAzureCredential()
);
csharp
builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{vaultName}.vault.azure.net/"),
    new DefaultAzureCredential()
);

Logging Security Events

安全事件日志记录

csharp
public class SecurityLogger
{
    private readonly ILogger<SecurityLogger> _logger;

    public SecurityLogger(ILogger<SecurityLogger> logger) => _logger = logger;

    public void LogLoginAttempt(string username, bool success, string ipAddress)
    {
        _logger.LogInformation(
            "Login attempt: User={Username}, Success={Success}, IP={IpAddress}",
            username, success, ipAddress
        );
    }

    public void LogAccessDenied(string userId, string resource, string ipAddress)
    {
        _logger.LogWarning(
            "Access denied: User={UserId}, Resource={Resource}, IP={IpAddress}",
            userId, resource, ipAddress
        );
    }

    // NEVER log sensitive data
    // _logger.LogInformation("Password: {Password}", password);  // NEVER!
}
csharp
public class SecurityLogger
{
    private readonly ILogger<SecurityLogger> _logger;

    public SecurityLogger(ILogger<SecurityLogger> logger) => _logger = logger;

    public void LogLoginAttempt(string username, bool success, string ipAddress)
    {
        _logger.LogInformation(
            "登录尝试:用户={Username}, 成功={Success}, IP={IpAddress}",
            username, success, ipAddress
        );
    }

    public void LogAccessDenied(string userId, string resource, string ipAddress)
    {
        _logger.LogWarning(
            "访问被拒绝:用户={UserId}, 资源={Resource}, IP={IpAddress}",
            userId, resource, ipAddress
        );
    }

    // 绝对不要记录敏感数据
    // _logger.LogInformation("密码: {Password}", password);  // 绝对禁止!
}

Anti-Patterns

反模式

Anti-PatternWhy It's BadCorrect Approach
String interpolation in SQLSQL injectionUse parameterized queries
Html.Raw(userInput)
XSS vulnerabilityUse default encoding
Storing secrets in appsettingsSecret exposureUse User Secrets/Key Vault
[AllowAnonymous]
everywhere
No authenticationApply selectively
Disabling HTTPS redirectionMan-in-the-middleKeep HTTPS enabled
Custom crypto implementationWeak encryptionUse built-in libraries
Catching all exceptionsHides security issuesLog and handle specifically
反模式危害正确做法
SQL中使用字符串插值存在SQL注入风险使用参数化查询
Html.Raw(userInput)
存在XSS漏洞使用默认编码
在appsettings中存储密钥密钥泄露使用用户密钥/密钥保管库
全局使用
[AllowAnonymous]
无身份验证保护选择性应用
禁用HTTPS重定向存在中间人攻击风险保持HTTPS启用
自定义加密实现加密强度不足使用内置库
捕获所有异常隐藏安全问题针对性记录和处理

Quick Troubleshooting

快速排查指南

IssueLikely CauseSolution
401 UnauthorizedJWT validation failedCheck issuer, audience, key
CORS errorOrigin not allowedAdd origin to CORS policy
Rate limit triggeredToo many requestsAdjust rate limiter settings
Password validation failsPolicy requirementsCheck Identity password options
NuGet vulnerabilityOutdated packageUpdate to patched version
User Secrets not loadingNot in DevelopmentCheck
ASPNETCORE_ENVIRONMENT
问题可能原因解决方案
401未授权JWT验证失败检查颁发者、受众、密钥
CORS错误来源未被允许将来源添加到CORS策略
触发限流请求次数过多调整限流设置
密码验证失败策略要求不满足检查Identity密码选项
NuGet漏洞包版本过时更新到已修复的版本
用户密钥未加载不在开发环境检查
ASPNETCORE_ENVIRONMENT

Security Scanning Commands

安全扫描命令

bash
undefined
bash
undefined

Dependency audit

依赖项审计

dotnet list package --vulnerable --include-transitive
dotnet list package --vulnerable --include-transitive

Security analyzers (add NuGet packages)

安全分析器(需添加NuGet包)

Microsoft.CodeAnalysis.NetAnalyzers

Microsoft.CodeAnalysis.NetAnalyzers

SecurityCodeScan.VS2019

SecurityCodeScan.VS2019

Snyk

Snyk扫描

snyk test
snyk test

Check for secrets

检查密钥泄露

gitleaks detect trufflehog git file://.
gitleaks detect trufflehog git file://.

SAST with Semgrep

使用Semgrep进行SAST扫描

semgrep --config=p/csharp .
undefined
semgrep --config=p/csharp .
undefined

Related Skills

相关技能

  • OWASP Top 10:2025
  • OWASP General
  • Secrets Management
  • Supply Chain Security
  • OWASP Top 10:2025
  • 通用OWASP
  • 密钥管理
  • 供应链安全