Security & resource hardening: eliminate CPU/disk attack surface
Addresses production CPU spike incident. Key changes: - Guard OTel exporter behind OTEL_EXPORTER_OTLP_ENDPOINT env var; filter tracing to /api paths only — unconditional export was primary suspect - Remove /healthz endpoint entirely (unauthenticated, hit DB on every call) - Replace KnownUserMiddleware with POST /api/users/me called once on login from TokenSync — eliminates unconditional DB write on every request - Add DB indexes: (BudgetId, IsDeleted) on Incomes/Outgos, OwnerUserId on Budgets, SharedWithUserId and (IsPending, SharedWithEmail) on BudgetShares - Move UseRateLimiter() before UseStaticFiles() so all requests are throttled - Replace full-array reorder with move-by-position (id + newIndex) — bounded input, fewer DB writes, better API design - Lock ForwardedHeaders to 172.20.0.0/16 subnet; fixes KnownNetworks deprecation warning (0 warnings in build now) - Add AsNoTracking() to all read-only queries in Summary/Incomes/OutgosController - FrequencyCalculator returns 0 for unknown enum values instead of throwing - Thread.Sleep → await Task.Delay in OIDC startup loop - AllowedHosts locked to budget.stwaddle.com Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Budget.Infrastructure.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddHardeningIndexes : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Outgos_BudgetId",
|
||||
table: "Outgos");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Incomes_BudgetId",
|
||||
table: "Incomes");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Outgos_BudgetId_IsDeleted",
|
||||
table: "Outgos",
|
||||
columns: new[] { "BudgetId", "IsDeleted" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Incomes_BudgetId_IsDeleted",
|
||||
table: "Incomes",
|
||||
columns: new[] { "BudgetId", "IsDeleted" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BudgetShares_IsPending_SharedWithEmail",
|
||||
table: "BudgetShares",
|
||||
columns: new[] { "IsPending", "SharedWithEmail" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BudgetShares_SharedWithUserId",
|
||||
table: "BudgetShares",
|
||||
column: "SharedWithUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Budgets_OwnerUserId",
|
||||
table: "Budgets",
|
||||
column: "OwnerUserId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Outgos_BudgetId_IsDeleted",
|
||||
table: "Outgos");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Incomes_BudgetId_IsDeleted",
|
||||
table: "Incomes");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BudgetShares_IsPending_SharedWithEmail",
|
||||
table: "BudgetShares");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BudgetShares_SharedWithUserId",
|
||||
table: "BudgetShares");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Budgets_OwnerUserId",
|
||||
table: "Budgets");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Outgos_BudgetId",
|
||||
table: "Outgos",
|
||||
column: "BudgetId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Incomes_BudgetId",
|
||||
table: "Incomes",
|
||||
column: "BudgetId");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user