fix(gameserver): P0 security & integrity hardening #46
No reviewers
Labels
No labels
alpha:wave-0
alpha:wave-1
alpha:wave-2
alpha:wave-3
area:assets
area:combat
area:ecology
area:infra
area:render
area:scripting
area:ui
area:world
enhancement
epic
migration
post-alpha
roadmap
tech-debt
type:bug
type:chore
type:design
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
marco/IsoMmo!46
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/p0-security-hardening"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The four HIGH security/integrity findings from the critical code review (report in chat). All are server-authority / anti-tamper / data-integrity.
{"type":"move","direction":99}deserialized to an undefinedDirectionand threw inside the sharedWorld.Tick(), aborting the tick for everyone (re-sendable → repeatable world freeze). Fixed at the boundary:JsonStringEnumConverter(allowIntegerValues:false)rejects out-of-range enums at parse (covers all wire enums) +Enum.IsDefinedguard on moves.WebSocketConnectionnow has a bounded outbound queue drained by a background pump (RunSendPumpAsync); sends are non-blocking enqueues, overflow (256 behind) closes the connection, and theClosedtoken ends the receive loop so a dead send side tears the session down.finallyfreed the connection slot before tearing down world state, so a reconnect couldTryAddand have its fresh state wiped. Now teardown runs while still holding the slot, which is released last and identity-checked (ConnectionManager.TryRemove(id, connection)).WorldPersisterre-read inventory/skills lazily per player after snapshotting the online set, so a mid-flush disconnect made it persist a blanked record (items + skills wiped on next login). Now one atomicWorld.PersistableSnapshot()captures position+inventory+skills under a single lock.Regression tests: enum rejection (
ProtocolJsonTests), outbound-queue overflow→close (WebSocketConnectionTests), identity-checked removal (ConnectionManagerTests), atomic snapshot (WorldTests). Whole suite green (GameServer 113), 0 warnings, csharpier clean.Definition of Done
Four findings from the code review, all server-authority / integrity: - Enum DoS: reject out-of-range wire enums at parse (JsonStringEnumConverter allowIntegerValues:false) + Enum.IsDefined guard on moves, so a crafted {"direction":99} can no longer throw inside the shared tick and freeze the world. - Slow-client stall: WebSocketConnection now has a bounded outbound queue drained by a background pump; sends never touch the socket inline, so one stuck client can't block the tick loop. Overflow closes the connection (Closed token also ends the receive loop). - Reconnect race: tear down world/interest state while still holding the connection slot and release it last, identity-checked (ConnectionManager.TryRemove(id, connection)), so a reconnect can't have its fresh state wiped by the old session's teardown. - Persist data loss: WorldPersister reads position+inventory+skills via one atomic World.PersistableSnapshot() instead of lazy per-player re-reads, so a mid-flush disconnect can't blank a player's record.