Harden seat transfer phrases (security review finding)
Three words from 32 was ~15 bits — enumerable within a code's lifetime against an unthrottled endpoint. Now: 64-word list, 4-word phrases (~24 bits / 16.7M combinations), a per-connection cap of 5 failed claims, and a global backstop that voids all pending codes and cools the endpoint after 30 failures in 10 minutes. Codes stay speakable; a brute force now gets ~35 guesses against 16.7M before the door closes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
2184721ab4
commit
ce8b6a315b
@@ -36,6 +36,7 @@ interface Session {
|
||||
socket: WebSocket;
|
||||
playerId: PlayerId | null;
|
||||
roomId: string | null;
|
||||
claimFails: number;
|
||||
}
|
||||
|
||||
const sessions = new Set<Session>();
|
||||
@@ -70,7 +71,7 @@ function broadcastRoomState(room: Room): void {
|
||||
}
|
||||
|
||||
wss.on("connection", (socket) => {
|
||||
const session: Session = { socket, playerId: null, roomId: null };
|
||||
const session: Session = { socket, playerId: null, roomId: null, claimFails: 0 };
|
||||
sessions.add(session);
|
||||
send(socket, { type: "welcome", game: "wizwar" });
|
||||
|
||||
@@ -142,8 +143,15 @@ wss.on("connection", (socket) => {
|
||||
break;
|
||||
}
|
||||
case "claimTransfer": {
|
||||
if (session.claimFails >= 5) {
|
||||
return send(socket, { type: "error", message: "too many attempts on this connection — reconnect and mint a fresh phrase" });
|
||||
}
|
||||
const result = claimTransferCode(String(msg.code ?? ""));
|
||||
if ("error" in result) return send(socket, { type: "error", message: result.error });
|
||||
if ("error" in result) {
|
||||
session.claimFails++;
|
||||
return send(socket, { type: "error", message: result.error });
|
||||
}
|
||||
session.claimFails = 0;
|
||||
send(socket, { type: "transferClaimed", seat: result });
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user