Security hardening: Fix critical JWT, rate limiting, and deployment issues

This commit is contained in:
2025-09-28 18:52:05 +01:00
parent 586d491b83
commit 1b46222300
3 changed files with 130 additions and 15 deletions

View File

@@ -6,6 +6,7 @@ using LittleShop.Data;
using LittleShop.Services;
using FluentValidation;
using Serilog;
using AspNetCoreRateLimit;
var builder = WebApplication.CreateBuilder(args);
@@ -42,8 +43,58 @@ else
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
}
// Rate Limiting - protect anonymous endpoints
builder.Services.AddMemoryCache();
builder.Services.Configure<AspNetCoreRateLimit.IpRateLimitOptions>(options =>
{
options.EnableEndpointRateLimiting = true;
options.StackBlockedRequests = false;
options.HttpStatusCode = 429;
options.RealIpHeader = "X-Real-IP";
options.ClientIdHeader = "X-ClientId";
options.GeneralRules = new List<AspNetCoreRateLimit.RateLimitRule>
{
new AspNetCoreRateLimit.RateLimitRule
{
Endpoint = "*/api/orders/by-identity/*",
Period = "1m",
Limit = 10
},
new AspNetCoreRateLimit.RateLimitRule
{
Endpoint = "*/api/orders/by-customer/*",
Period = "1m",
Limit = 10
},
new AspNetCoreRateLimit.RateLimitRule
{
Endpoint = "*",
Period = "1s",
Limit = 10
},
new AspNetCoreRateLimit.RateLimitRule
{
Endpoint = "*",
Period = "1m",
Limit = 100
}
};
});
builder.Services.AddSingleton<AspNetCoreRateLimit.IIpPolicyStore, AspNetCoreRateLimit.MemoryCacheIpPolicyStore>();
builder.Services.AddSingleton<AspNetCoreRateLimit.IRateLimitCounterStore, AspNetCoreRateLimit.MemoryCacheRateLimitCounterStore>();
builder.Services.AddSingleton<AspNetCoreRateLimit.IRateLimitConfiguration, AspNetCoreRateLimit.RateLimitConfiguration>();
builder.Services.AddSingleton<AspNetCoreRateLimit.IProcessingStrategy, AspNetCoreRateLimit.AsyncKeyLockProcessingStrategy>();
// Authentication - Cookie for Admin Panel, JWT for API
var jwtKey = builder.Configuration["Jwt:Key"] ?? "ThisIsASuperSecretKeyForJWTAuthenticationThatIsDefinitelyLongerThan32Characters!";
var jwtKey = builder.Configuration["Jwt:Key"];
if (string.IsNullOrEmpty(jwtKey))
{
Log.Fatal("🚨 SECURITY: Jwt:Key configuration is missing. Application cannot start securely.");
throw new InvalidOperationException(
"JWT:Key must be configured in environment variables or user secrets. " +
"Set the Jwt__Key environment variable or use: dotnet user-secrets set \"Jwt:Key\" \"<your-secure-key>\"");
}
var jwtIssuer = builder.Configuration["Jwt:Issuer"] ?? "LittleShop";
var jwtAudience = builder.Configuration["Jwt:Audience"] ?? "LittleShop";
@@ -251,6 +302,9 @@ if (!app.Environment.IsDevelopment())
app.UseHsts(); // Use HSTS for production security
}
// Add rate limiting middleware (after CORS, before authentication)
app.UseIpRateLimiting();
app.UseStaticFiles(); // Enable serving static files
app.UseAuthentication();
app.UseAuthorization();
@@ -298,9 +352,27 @@ app.MapGet("/api/version", () =>
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<LittleShopContext>();
// Ensure database is created (temporary while fixing migrations)
context.Database.EnsureCreated();
// Use proper migrations in production, EnsureCreated only for development/testing
if (app.Environment.IsProduction())
{
Log.Information("Production environment: Applying database migrations...");
try
{
context.Database.Migrate();
Log.Information("Database migrations applied successfully");
}
catch (Exception ex)
{
Log.Fatal(ex, "Database migration failed. Application cannot start.");
throw;
}
}
else
{
Log.Information("Development/Testing environment: Using EnsureCreated");
context.Database.EnsureCreated();
}
// Seed default admin user
var authService = scope.ServiceProvider.GetRequiredService<IAuthService>();
@@ -310,10 +382,14 @@ using (var scope = app.Services.CreateScope())
var dataSeeder = scope.ServiceProvider.GetRequiredService<IDataSeederService>();
await dataSeeder.SeedSampleDataAsync();
// Seed system settings - enable test currencies for development
var systemSettings = scope.ServiceProvider.GetRequiredService<ISystemSettingsService>();
await systemSettings.SetTestCurrencyEnabledAsync("TBTC", true);
await systemSettings.SetTestCurrencyEnabledAsync("TLTC", true);
// Seed system settings - enable test currencies only in development
if (app.Environment.IsDevelopment())
{
Log.Information("Development environment: Enabling test currencies");
var systemSettings = scope.ServiceProvider.GetRequiredService<ISystemSettingsService>();
await systemSettings.SetTestCurrencyEnabledAsync("TBTC", true);
await systemSettings.SetTestCurrencyEnabledAsync("TLTC", true);
}
}
Log.Information("LittleShop API starting up...");