Vote page: explicit no-store (the antiforgery write no longer supplies it), handler must match the request, empty Origin counts as present

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-11 00:15:13 +02:00
commit d3a7611f2a
2 changed files with 10 additions and 1 deletions

View file

@ -18,7 +18,7 @@ public static class CastRequestGuard
}
var origin = request.Headers.Origin;
if (origin.Count > 0)
if (request.Headers.ContainsKey("Origin"))
{
return origin.Count == 1 && string.Equals(origin[0], site.GetLeftPart(UriPartial.Authority), StringComparison.Ordinal);
}

View file

@ -12,6 +12,7 @@ namespace Bifrost.Web.Pages.Mill;
// The anonymous vote page. Counts and the visitor's own stance come from ConceptAppraisalService on every GET; the
// voter key is decided by VoterIdentity.For from the actor and the device id VoterKeyResolver reads.
[IgnoreAntiforgeryToken]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public sealed class VoteModel(
ICurrentBifrostActorAccessor actorAccessor,
ConceptAppraisalService appraisals,
@ -40,6 +41,14 @@ public sealed class VoteModel(
return;
}
// The handler the request names must be the handler selected: GET ?handler=Up has no OnGetUp to run.
var named = context.HttpContext.Request.Query["handler"].ToString();
if (string.IsNullOrEmpty(named) != string.IsNullOrEmpty(context.HandlerMethod.Name))
{
context.Result = new StatusCodeResult(StatusCodes.Status400BadRequest);
return;
}
if (HttpMethods.IsPost(method) && !CastRequestGuard.Allows(context.HttpContext.Request, host.Value))
{
context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);