Skip to content

Phase 0: authorization and CSRF hardening - #3065

Closed
mojjj wants to merge 1 commit into
ZeroK-RTS:masterfrom
mojjj:security/phase0
Closed

mojjj wants to merge 1 commit into
ZeroK-RTS:masterfrom
mojjj:security/phase0

Conversation

@mojjj

@mojjj mojjj commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

following plan from
https://claude.ai/artifact/6F5ge7HuKds3pSscdpDwLM?sk=EseoKdX4iftoAycKuNy3rw

phase 0

Rebuilt against current master. Closes the mutating endpoints that are reachable without authorization or without an anti-forgery token, plus two config issues. No behaviour change beyond the fixes, and nothing here depends on the wider modernization plan.

Authorization - these had no [Auth] at all:

  • MapsController.RemovePlanetIcon / SubmitPlanetIcon / PlanetImageSelect were gated in the UI only; the actions accepted anonymous requests and wrote to the database. Now [Auth(Role = AdminLevel.Moderator)].
  • MyController.Reset, MapBansController.Update, PlanetwarsController.AppointRole / RecallRole, and FactionsController CancelTreaty / CounterProposal / ModifyTreaty / SetTopic relied on an exception or a null reference to fail closed for anonymous callers. Now [Auth].

CSRF - 32 state-changing actions now require [HttpPost] and [ValidateAntiForgeryToken]. Upstream had already covered a good part of this surface; these are the admin and destructive actions it had not reached, including the whole PlanetwarsAdminController (galaxy delete, start, randomize maps, team sizes, wormholes, own planets), forum thread moderation, news and lobby news posting and deletion, poll creation and visibility, mission delete and undelete, blocked VPN host and company removal, contributions, and planet rename.

Forms that already posted gained @Html.AntiForgeryToken(). GET links became @Html.PostLink / @Html.PostImageLink (new AppCode/PostLinkExtensions.cs) - a form carrying the token with a submit button styled as a link, reusing the existing .js_confirm dialog. site_main.js now skips .postlink-button when it buttonifies :submit with jQuery UI, so these keep looking like links.

AddWormholes and OwnPlanets had no call site and were reachable only by typing a URL; making them POST-only would have stranded them, so they now have links in PlanetwarsAdminIndex alongside their siblings.

Config:

  • customErrors Off -> RemoteOnly. Web.Release.config already strips compilation debug, but it does not touch customErrors, so stack traces were reaching the public.
  • Removed the commented-out ModStatsConnectionString; the block was dead but the password was still sitting in the file.

Passwords:

  • BCrypt work factor 4 -> 10 via a named constant. Existing hashes carry their own cost inside the hash, so Verify keeps working and only newly set passwords pay the higher cost.

Not built: ZkData does not compile under mono 6.12 - System.IO.Compression facade version conflict at MissionService/MissionUpdater.cs:69, reproduced identically on unmodified master, so it is an artifact of the container and not of these changes. AppCode/PostLinkExtensions.cs was compiled standalone against System.Web.Mvc 5.2.3 and is clean; the remaining C# changes are attribute insertions. Razor views are unverified either way - mono has no aspnet_compiler.exe. Needs a Windows build and a pass over the admin screens.

Deliberately deferred:

  • requestValidationMode="2.0" and requestPathInvalidCharacters="" stay as they are; restoring the defaults would likely reject legitimate map, replay and wiki names in route segments.
  • Roughly 30 user-level mutating actions (forum voting, clan and faction joins, ratings, PlanetWars structures and dropships) still accept GET.

Rebuilt against current master. Closes the mutating endpoints that are reachable
without authorization or without an anti-forgery token, plus two config issues.
No behaviour change beyond the fixes, and nothing here depends on the wider
modernization plan.

Authorization - these had no [Auth] at all:
- MapsController.RemovePlanetIcon / SubmitPlanetIcon / PlanetImageSelect were
  gated in the UI only; the actions accepted anonymous requests and wrote to the
  database. Now [Auth(Role = AdminLevel.Moderator)].
- MyController.Reset, MapBansController.Update,
  PlanetwarsController.AppointRole / RecallRole, and FactionsController
  CancelTreaty / CounterProposal / ModifyTreaty / SetTopic relied on an
  exception or a null reference to fail closed for anonymous callers. Now [Auth].

CSRF - 32 state-changing actions now require [HttpPost] and
[ValidateAntiForgeryToken]. Upstream had already covered a good part of this
surface; these are the admin and destructive actions it had not reached,
including the whole PlanetwarsAdminController (galaxy delete, start, randomize
maps, team sizes, wormholes, own planets), forum thread moderation, news and
lobby news posting and deletion, poll creation and visibility, mission delete
and undelete, blocked VPN host and company removal, contributions, and planet
rename.

Forms that already posted gained @Html.AntiForgeryToken(). GET links became
@Html.PostLink / @Html.PostImageLink (new AppCode/PostLinkExtensions.cs) - a form
carrying the token with a submit button styled as a link, reusing the existing
.js_confirm dialog. site_main.js now skips .postlink-button when it buttonifies
:submit with jQuery UI, so these keep looking like links.

AddWormholes and OwnPlanets had no call site and were reachable only by typing a
URL; making them POST-only would have stranded them, so they now have links in
PlanetwarsAdminIndex alongside their siblings.

Config:
- customErrors Off -> RemoteOnly. Web.Release.config already strips
  compilation debug, but it does not touch customErrors, so stack traces were
  reaching the public.
- Removed the commented-out ModStatsConnectionString; the block was dead but the
  password was still sitting in the file.

Passwords:
- BCrypt work factor 4 -> 10 via a named constant. Existing hashes carry their
  own cost inside the hash, so Verify keeps working and only newly set passwords
  pay the higher cost.

Not built: ZkData does not compile under mono 6.12 - System.IO.Compression
facade version conflict at MissionService/MissionUpdater.cs:69, reproduced
identically on unmodified master, so it is an artifact of the container and not
of these changes. AppCode/PostLinkExtensions.cs was compiled standalone against
System.Web.Mvc 5.2.3 and is clean; the remaining C# changes are attribute
insertions. Razor views are unverified either way - mono has no
aspnet_compiler.exe. Needs a Windows build and a pass over the admin screens.

Deliberately deferred:
- requestValidationMode="2.0" and requestPathInvalidCharacters="" stay as they
  are; restoring the defaults would likely reject legitimate map, replay and
  wiki names in route segments.
- Roughly 30 user-level mutating actions (forum voting, clan and faction joins,
  ratings, PlanetWars structures and dropships) still accept GET.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mojjj
mojjj marked this pull request as draft September 16, 2026 14:01
@mojjj mojjj closed this Sep 16, 2026
@mojjj
mojjj deleted the security/phase0 branch September 17, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants