Harden CSRF/CSP and add hash version upgrades

This commit is contained in:
2026-02-18 20:51:18 +01:00
parent 3c7f3d2114
commit a130cba41a
23 changed files with 627 additions and 57 deletions

View File

@@ -1,4 +1,6 @@
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using GameList.Tests.Support;
namespace GameList.Tests;
@@ -36,4 +38,49 @@ public class MiddlewareTests
var resp = await client.GetAsync("/api/state");
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
}
[Fact]
public async Task Mutating_authenticated_request_without_origin_is_rejected()
{
await using var factory = new TestWebApplicationFactory();
var client = factory.CreateClientWithCookies();
var register = await client.RegisterAsync("csrfm");
register.EnsureSuccessStatusCode();
await client.CreateSuggestionAsync("Seed");
await client.PostAsJsonAsync("/api/me/phase/next", new { });
client.DefaultRequestHeaders.Remove("Origin");
var response = await client.PostAsJsonAsync("/api/votes/finalize", new
{
Final = true
});
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var body = await response.Content.ReadFromJsonAsync<JsonElement>();
Assert.Equal("CSRF validation failed.", body.GetProperty("error").GetString());
}
[Fact]
public async Task Mutating_authenticated_request_with_cross_origin_is_rejected()
{
await using var factory = new TestWebApplicationFactory();
var client = factory.CreateClientWithCookies();
var register = await client.RegisterAsync("csrfx");
register.EnsureSuccessStatusCode();
await client.CreateSuggestionAsync("Seed");
await client.PostAsJsonAsync("/api/me/phase/next", new { });
client.DefaultRequestHeaders.Remove("Origin");
client.DefaultRequestHeaders.TryAddWithoutValidation("Origin", "https://evil.example");
var response = await client.PostAsJsonAsync("/api/votes/finalize", new
{
Final = true
});
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var body = await response.Content.ReadFromJsonAsync<JsonElement>();
Assert.Equal("CSRF validation failed.", body.GetProperty("error").GetString());
}
}