feat: dedicated server security hardening

Comprehensive security system to protect against packet-sniffing attacks,
XUID harvesting, privilege escalation, bot flooding, and XUID impersonation.

- Stream cipher: per-session XOR cipher with 4-message handshake via
  CustomPayloadPacket (MC|CKey, MC|CAck, MC|COn). Negotiated per-connection,
  backwards compatible (old clients/servers fall back to plaintext).
- Security gate: buffers all game data until cipher handshake completes,
  preventing unsecured clients from receiving any XUIDs or game state.
- Cipher handshake enforcer: kicks clients that don't complete the handshake
  within 5 seconds (configurable via require-secure-client).
- Identity tokens: persistent per-XUID tokens in identity-tokens.json,
  issued over the encrypted channel, verified on reconnect. Prevents XUID
  replay attacks. Client stores server-specific tokens.
- PROXY protocol v1: parses real client IPs from playit.gg tunnel headers
  so rate limiting, IP bans, and XUID spoof detection work per-player.
- Rate limiting: per-IP sliding window (default 5 connections/30s) with
  pending connection cap (default 10).
- Privilege hardening: OP requires ops.json, live checks on every command
  and privilege packet. Host-only server settings changes.
- XUID stripping: PreLoginPacket response sends INVALID_XUID placeholders.
- Packet validation: readUtf global string cap, reduced max packet size,
  stream desync protection on oversized strings.
- OpManager: persistent ops.json with XUID-based OP list.
- Whitelist improvements: whitelist add accepts player names with ambiguity
  detection, XUID cache from login attempts.
- revoketoken command: revoke identity tokens for players who lost theirs.
- server.log: persistent log file written alongside console output with
  flush-per-write to survive crashes.
- CLI security logging: consolidated per-join security summary with cipher
  status, token status, XUID, and real IP. Security warnings for kicks,
  spoofing, and unauthorized commands.
This commit is contained in:
itsRevela
2026-03-28 19:18:06 -05:00
parent ed3fffcc6a
commit ba3ebe666c
42 changed files with 3293 additions and 34 deletions

View File

@@ -11,6 +11,9 @@
#include "..\ServerLogManager.h"
#include "..\ServerProperties.h"
#include "..\ServerShutdown.h"
#include "..\Security\SecurityConfig.h"
#include "..\Security\RateLimiter.h"
#include "..\Security\IdentityTokenManager.h"
#include "..\WorldManager.h"
#include "..\Console\ServerCli.h"
#include "Tesselator.h"
@@ -416,6 +419,41 @@ int main(int argc, char **argv)
return 2;
}
accessShutdownGuard.Activate();
{
ServerRuntime::Security::SecuritySettings secSettings;
secSettings.hidePlayerListPreLogin = serverProperties.hidePlayerListPreLogin;
secSettings.rateLimitConnectionsPerWindow = serverProperties.rateLimitConnectionsPerWindow;
secSettings.rateLimitWindowSeconds = serverProperties.rateLimitWindowSeconds;
secSettings.maxPendingConnections = serverProperties.maxPendingConnections;
secSettings.requireChallengeToken = serverProperties.requireChallengeToken;
secSettings.enableStreamCipher = serverProperties.enableStreamCipher;
secSettings.requireSecureClient = serverProperties.requireSecureClient;
secSettings.proxyProtocol = serverProperties.proxyProtocol;
ServerRuntime::Security::InitializeSettings(secSettings);
LogInfof("startup", "Security: hide-player-list=%s, rate-limit=%d/%ds, max-pending=%d, challenge-token=%s, stream-cipher=%s, require-secure-client=%s",
secSettings.hidePlayerListPreLogin ? "true" : "false",
secSettings.rateLimitConnectionsPerWindow,
secSettings.rateLimitWindowSeconds,
secSettings.maxPendingConnections,
secSettings.requireChallengeToken ? "required" : "optional",
secSettings.enableStreamCipher ? "enabled" : "disabled",
secSettings.requireSecureClient ? "true" : "false");
if (secSettings.proxyProtocol)
{
LogInfof("startup", "PROXY protocol: enabled (all connections must send PROXY v1 header)");
}
if (secSettings.requireSecureClient && !secSettings.enableStreamCipher)
{
LogInfof("startup", "WARNING: require-secure-client is enabled but enable-stream-cipher is disabled -- secure client enforcement will have no effect");
}
if (secSettings.requireChallengeToken)
{
ServerRuntime::Security::GetIdentityTokenManager().Initialize("identity-tokens.json");
}
}
LogInfof("startup", "LAN advertise: %s", serverProperties.lanAdvertise ? "enabled" : "disabled");
LogInfof("startup", "Whitelist: %s", serverProperties.whiteListEnabled ? "enabled" : "disabled");
LogInfof("startup", "Spawn protection radius: %d", serverProperties.spawnProtectionRadius);