Tổng Quan OWASP Top 10 (2021)
OWASP Top 10 là danh sách 10 rủi ro bảo mật web application nghiêm trọng nhất, được cập nhật định kỳ. Dưới đây là phân tích từng risk với context .NET cụ thể.
A01 - Broken Access Control
Risk: User truy cập tài nguyên ngoài quyền hạn.
csharp// VULNERABLE: Không kiểm tra ownership
[HttpGet("orders/{orderId}")]
public async Task<IActionResult> GetOrder(int orderId)
{
var order = await _db.Orders.FindAsync(orderId);
return Ok(order); // Bất kỳ user nào cũng xem được order người khác
}
// SECURE: Kiểm tra ownership + authorization
[HttpGet("orders/{orderId}")]
[Authorize]
public async Task<IActionResult> GetOrder(int orderId)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var order = await _db.Orders
.Where(o => o.Id == orderId && o.UserId == userId)
.FirstOrDefaultAsync();
if (order is null) return NotFound();
return Ok(order);
}
Best practices:
- Dùng Policy-based authorization thay vì kiểm tra role cứng
- Implement resource-based authorization với
IAuthorizationHandler - Default deny - chỉ cho phép những gì explicitly granted
A02 - Cryptographic Failures
csharp// VULNERABLE: MD5 cho password
var hash = MD5.HashData(Encoding.UTF8.GetBytes(password));
// SECURE: ASP.NET Identity PasswordHasher (PBKDF2 with auto-salt)
var hasher = new PasswordHasher<ApplicationUser>();
var hashed = hasher.HashPassword(user, password);
var result = hasher.VerifyHashedPassword(user, hashed, inputPassword);
Checklist:
- Dùng
DataProtection APIcho encryption at rest - TLS 1.2+ cho tất cả connections
- Không hardcode secrets - dùng Azure Key Vault hoặc User Secrets
A03 - Injection
SQL Injection
csharp// VULNERABLE: String concatenation
var sql = $"SELECT * FROM Users WHERE Name = '{input}'";
await _db.Users.FromSqlRaw(sql).ToListAsync();
// SECURE: Parameterized query
await _db.Users
.FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {input}")
.ToListAsync();
// BETTER: Use LINQ (EF Core auto-parameterizes)
await _db.Users.Where(u => u.Name == input).ToListAsync();
Command Injection
csharp// VULNERABLE
Process.Start("cmd", $"/c ping {userInput}");
// SECURE: Validate và whitelist
if (!IPAddress.TryParse(userInput, out var ip))
return BadRequest("Invalid IP address");
A04 - Insecure Design
Mitigation pattern: Threat modeling early in SDLC
| Design Issue | Mitigation |
|---|---|
| Không rate limit | Implement RateLimiter middleware (.NET 7+) |
| Thiếu input validation | FluentValidation + DataAnnotations |
| Business logic bypass | Server-side validation, không trust client |
csharp// Rate limiting trong .NET 7+
builder.Services.AddRateLimiter(opts =>
{
opts.AddFixedWindowLimiter("api", config =>
{
config.PermitLimit = 100;
config.Window = TimeSpan.FromMinutes(1);
config.QueueLimit = 0;
});
opts.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});
app.UseRateLimiter();
A05 - Security Misconfiguration
csharp// Security Headers Middleware
public class SecurityHeadersMiddleware
{
private readonly RequestDelegate _next;
public SecurityHeadersMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var headers = context.Response.Headers;
// Chống clickjacking
headers["X-Frame-Options"] = "DENY";
// Chống MIME-type sniffing
headers["X-Content-Type-Options"] = "nosniff";
// Chống XSS (legacy browsers)
headers["X-XSS-Protection"] = "1; mode=block";
// Content Security Policy
headers["Content-Security-Policy"] =
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'";
// Referrer Policy
headers["Referrer-Policy"] = "strict-origin-when-cross-origin";
// Strict Transport Security
headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains";
// Không expose server info
headers.Remove("Server");
headers.Remove("X-Powered-By");
await _next(context);
}
}
A06 - Vulnerable and Outdated Components
bash# Scan NuGet vulnerabilities
dotnet list package --vulnerable --include-transitive
# Trong CI/CD pipeline
dotnet list package --vulnerable --format json | jq '.projects[].frameworks[].topLevelPackages[] | select(.vulnerabilities)'
Best practices:
- Enable Dependabot hoặc Renovate cho auto PR updates
- Audit transitive dependencies - không chỉ direct
- Pin major versions, auto-update patch versions
A07 - Identification and Authentication Failures
csharp// ASP.NET Identity configuration tối ưu
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(opts =>
{
// Password policy
opts.Password.RequiredLength = 12;
opts.Password.RequireDigit = true;
opts.Password.RequireUppercase = true;
opts.Password.RequireNonAlphanumeric = true;
// Lockout policy
opts.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
opts.Lockout.MaxFailedAccessAttempts = 5;
opts.Lockout.AllowedForNewUsers = true;
// User settings
opts.User.RequireUniqueEmail = true;
opts.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
// JWT configuration với rotation
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opts =>
{
opts.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ClockSkew = TimeSpan.FromMinutes(1), // Giảm từ default 5 phút
ValidIssuer = config["Jwt:Issuer"],
ValidAudience = config["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(config["Jwt:Key"]!))
};
});
A08 - Software and Data Integrity Failures
- Verify NuGet package signatures
- Dùng lock files (
packages.lock.json) cho reproducible builds - CI/CD pipeline: restrict who can modify deployment scripts
- Implement Subresource Integrity (SRI) cho CDN scripts
A09 - Security Logging and Monitoring Failures
csharp// Audit logging cho security events
public class SecurityAuditService
{
private readonly ILogger<SecurityAuditService> _logger;
public SecurityAuditService(ILogger<SecurityAuditService> logger)
=> _logger = logger;
public void LogAuthSuccess(string userId, string ipAddress)
{
_logger.LogInformation(
"AUTH_SUCCESS: UserId={UserId} IP={IpAddress} Time={Time}",
userId, ipAddress, DateTimeOffset.UtcNow);
}
public void LogAuthFailure(string username, string ipAddress, string reason)
{
_logger.LogWarning(
"AUTH_FAILURE: Username={Username} IP={IpAddress} Reason={Reason}",
username, ipAddress, reason);
}
public void LogPrivilegeEscalation(string userId, string action)
{
_logger.LogCritical(
"PRIVILEGE_ESCALATION: UserId={UserId} Action={Action}",
userId, action);
}
}
A10 - Server-Side Request Forgery (SSRF)
csharp// VULNERABLE: User controls URL
[HttpGet("fetch")]
public async Task<IActionResult> Fetch([FromQuery] string url)
{
var content = await _httpClient.GetStringAsync(url);
return Ok(content);
}
// SECURE: Whitelist allowed domains
private static readonly HashSet<string> AllowedHosts = new()
{
"api.trusted-partner.com",
"cdn.myapp.com"
};
[HttpGet("fetch")]
public async Task<IActionResult> Fetch([FromQuery] string url)
{
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return BadRequest("Invalid URL");
if (!AllowedHosts.Contains(uri.Host))
return Forbid();
if (uri.Scheme != "https")
return BadRequest("HTTPS required");
var content = await _httpClient.GetStringAsync(uri);
return Ok(content);
}
Security Checklist Summary
| Category | Action | Priority |
|---|---|---|
| Authentication | MFA, strong password policy | P1 |
| Authorization | Resource-based, least privilege | P1 |
| Input Validation | Server-side, whitelist approach | P1 |
| Encryption | TLS 1.2+, Key Vault for secrets | P1 |
| Headers | Security headers middleware | P2 |
| Dependencies | Automated vulnerability scanning | P2 |
| Logging | Security events, no sensitive data in logs | P2 |
| Rate Limiting | Per-user, per-endpoint | P2 |