mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
Fix winner stats spoofing exploit
Previously, winnerVotes was keyed only on winner, so a client could send the correct winner with spoofed allPlayersStats and have their vote count toward the majority. The key is now a SHA-256 hash of both winner and allPlayersStats together, so any stats divergence produces a distinct key that must independently reach majority. When the winner is confirmed, the log now includes votesByKey — a summary of every distinct key, its vote count, and winner value — making stat manipulation visible in the logs.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { createHash } from "crypto";
|
||||
import ipAnonymize from "ip-anonymize";
|
||||
import { Logger } from "winston";
|
||||
import WebSocket from "ws";
|
||||
@@ -1200,7 +1201,14 @@ export class GameServer {
|
||||
client.reportedWinner = clientMsg.winner;
|
||||
|
||||
// Add client vote
|
||||
const winnerKey = JSON.stringify(clientMsg.winner);
|
||||
const winnerKey = createHash("sha256")
|
||||
.update(
|
||||
JSON.stringify({
|
||||
winner: clientMsg.winner,
|
||||
allPlayersStats: clientMsg.allPlayersStats,
|
||||
}),
|
||||
)
|
||||
.digest("hex");
|
||||
if (!this.winnerVotes.has(winnerKey)) {
|
||||
this.winnerVotes.set(winnerKey, { ips: new Set(), winner: clientMsg });
|
||||
}
|
||||
@@ -1227,6 +1235,12 @@ export class GameServer {
|
||||
`Winner determined by ${potentialWinner.ips.size}/${activeUniqueIPs.size} active IPs`,
|
||||
{
|
||||
winnerKey: winnerKey,
|
||||
numKeys: this.winnerVotes.size,
|
||||
votesByKey: [...this.winnerVotes.entries()].map(([key, v]) => ({
|
||||
key,
|
||||
voteCount: v.ips.size,
|
||||
winner: v.winner.winner,
|
||||
})),
|
||||
},
|
||||
);
|
||||
this.archiveGame();
|
||||
|
||||
Reference in New Issue
Block a user