닉네임 랭킹의 규칙과 한계: 만든 쪽의 설명과 부탁
가이드 · 2026-10-08 · GamePool 편집팀
GamePool의 닉네임 랭킹은 현재 30개 게임에 붙어 있습니다. 회원가입도 비밀번호도 없이 3글자 닉네임만 적으면 오늘 순위와 역대 순위에 이름이 오릅니다. 이렇게 단순하게 만들면 곧바로 어려운 문제가 따라옵니다. 누구나 아무 점수나 보낼 수 있다는 것입니다. 이 글은 랭킹 서버(worker/index.js)와 게임 쪽 코드(games/_shared/rank.js)에 들어 있는 규칙이 무엇이고, 왜 그렇게 정했으며, 어디까지 막을 수 있고 어디부터 못 막는지를 소스 기준으로 설명합니다. 마지막에는 이 구조에서 이용자에게 부탁드릴 매너를 적었습니다.
게임 하나, 난이도 하나마다 저장소 하나
랭킹은 클라우드플레어 워커의 Durable Object(SQLite)에 저장됩니다. 저장소 이름이 게임 id와 난이도를 이어 붙인 것(예: sudoku:hard)이라서, 지뢰찾기 고급의 기록이 초급과 섞일 일이 없습니다. 난이도별 표가 있는 게임은 세 곳입니다. 기억력 게임이 4개(쉬움~매우 어려움), 지뢰찾기와 스도쿠가 각각 3개이고, 이 세 게임은 작을수록 좋은 기록(횟수·초)이라 정렬 방향이 반대입니다. 저장소 안에는 날짜별 기록 표(daily)와 닉네임별 최고 기록 표(best) 두 개가 있습니다.
기록은 갱신이 될 때만 바뀝니다. 같은 닉네임이 같은 날 더 나쁜 기록을 보내면 무시하고, 더 좋은 기록만 덮어씁니다. 그래서 기록이 뒤로 가는 일은 없지만, 잘못 올라간 높은 점수도 스스로 낮아지지 않습니다. 순위는 나보다 좋은 기록의 개수에 1을 더해 계산하므로 같은 점수는 같은 순위를 받고, 표에서는 먼저 올린 사람이 위에 보입니다. 오늘 순위는 한국 시간(UTC+9) 기준 날짜가 바뀌면 새로 시작합니다. 오래된 날짜의 기록은 지워야 하는데, 정리 작업을 따로 돌리지 않고 기록이 등록될 때 5% 확률로 30일이 지난 줄을 지웁니다. 평균 20번에 한 번 정리하는 셈이고, 등록이 뜸한 게임에서는 정리가 늦을 수 있습니다.
닉네임 규칙과 실제로 걸러지는 예
서버의 닉네임 검사는 순서가 정해져 있습니다. 먼저 글자를 표준 형태로 합치고(NFC) 공백을 모두 지운 뒤, 1~3글자인지 보고, 한글 완성형·영문·숫자만 허용하는지 검사하고, 마지막으로 금칙어 29개가 들어 있는지 대소문자 구분 없이 확인합니다. 이 글을 쓰면서 같은 함수를 직접 돌려 본 결과는 다음과 같습니다. 가나다와 하늘, 민지, 한글a는 통과합니다. 가 나처럼 띄어 쓰면 공백이 지워져 가나가 됩니다. abcd(4글자)와 이모지는 통과하지 못합니다. 욕설은 물론 운영자·관리자·admin·gm이 들어간 이름도 막습니다.
여기에는 알려 드려야 할 부작용이 둘 있습니다. 하나는 부분 문자열 검사라서 정상적인 이름이 걸릴 수 있다는 점입니다. 실제로 Egm처럼 gm이 들어간 영문이나 보지마처럼 금칙어를 포함한 이름은 의도와 상관없이 등록되지 않습니다. 다른 하나는 금칙어 목록에 ㅅㅂ, ㅈㄴ처럼 자음만 쓴 항목이 있는데, 그 이전 단계인 한글 완성형만 허용하는 검사에서 먼저 걸리므로 이 항목은 사실상 쓰이지 않는다는 점입니다. 두 방어선이 겹쳐 있는 구조라 놔두었지만, 다음에 손볼 때 정리해야 할 부분입니다. 게임 쪽(rank.js)에도 같은 규칙의 검사가 있어서, 서버에 보내기 전에 한글·영문·숫자 1~3글자로 적어 달라는 안내가 먼저 나옵니다.
점수 검사: 상한이 있는 이유와 하한의 문제
서버는 점수가 정수이고 1 이상이며 게임별 상한 이하일 때만 받습니다. 상한은 게임의 규모에서 정했습니다. 레오니스의 상한은 160으로, 8개 챕터 × 20스테이지와 같은 숫자입니다. 돌파한 스테이지 수가 이보다 클 수 없기 때문입니다. 군단 점령전은 999, 챔피언 방어전은 1,000(웨이브), 점수제 게임은 10만~100억 단위로 넉넉히 두었습니다. 상한을 넘는 값은 오류로 돌려보냅니다. 극단적으로 큰 가짜 점수가 순위 맨 위에 오르는 것을 막기 위한 장치입니다.
이 방식에는 구조적 약점이 있습니다. 상한은 큰 가짜 점수를 막지만, 작을수록 좋은 기록(시간·횟수)은 반대로 작은 가짜 점수를 막을 수 없습니다. 서버가 받는 최소값은 1이라서, 누군가 지뢰찾기 고급에 1초를 보내면 서버는 그것이 사실인지 알 방법이 없습니다. 서버가 1 미만을 거절하기 때문에 지뢰찾기와 스도쿠는 Math.max(1, 초)로 맞춰 보내는데, 이는 정상 기록이 거절당하지 않게 하는 처리일 뿐 부정행위를 막는 장치가 아닙니다. 게임이 사용자 브라우저에서 돌아가는 한, 서버가 기록의 진위를 직접 검증할 수는 없다는 한계를 있는 그대로 인정합니다.
연타와 외부 요청을 막는 장치와 그 한계
기록 등록 요청에는 세 겹의 제한이 있습니다. 첫째, 요청의 출처(Origin)가 gamepool.kr, www.gamepool.kr, 개발용 localhost일 때만 받습니다. 다른 사이트의 페이지가 이용자의 브라우저를 이용해 대신 기록을 올리는 것을 막기 위한 것입니다. 둘째, 같은 IP에서는 3초 안에 다시 등록할 수 없고(slow_down), 이때는 잠시 후 다시 시도해 달라는 안내가 뜹니다. 셋째, 요청 본문이 200바이트를 넘으면 거절합니다. 닉네임과 점수만 담으면 되는 요청이라 충분히 작은 한도입니다.
이 장치들은 브라우저를 통한 우발적인 연타나 외부 사이트의 도용을 막을 뿐, 의지를 가진 사람이 직접 요청을 보내는 것까지 막지는 못합니다. Origin 헤더는 브라우저가 아닌 곳에서는 마음대로 적을 수 있기 때문입니다. 3초 제한도 서버 메모리의 목록에 IP를 적어 두는 방식이어서, 서버가 재시작되거나 목록이 5,000개를 넘어 비워지면 초기화됩니다. 또 닉네임에는 소유권이 없습니다. 비밀번호가 없으므로 누군가 내 닉네임으로 내 기록보다 좋은 점수를 보내면 그대로 내 이름의 기록이 됩니다. 반대로 나쁜 점수는 무시되므로 내 기록을 깎을 수는 없습니다. 이런 구조라서 우리는 닉네임을 인증된 신원이 아니라 표시되는 이름으로 부릅니다.
승수 랭킹이 브라우저 기록에 기대는 문제
장기·오목·알까기의 랭킹은 컴퓨터를 이긴 누적 승수입니다. 이 승수는 서버가 세는 것이 아니라 게임이 브라우저(localStorage)에 저장한 전적의 승 횟수를 그대로 보내는 방식입니다. 이 설계에는 두 가지 결과가 따릅니다. 하나는 사이트 데이터를 지우거나 다른 기기로 옮기면 승수가 0부터 다시 쌓인다는 점입니다. 서버에는 이전 최고 기록이 남아 있으므로, 새로 쌓은 승수가 이전 최고를 넘어서기 전까지는 순위표가 바뀌지 않습니다. 다른 하나는 게임 코드에 오류가 있으면 틀린 숫자가 그대로 올라간다는 점입니다.
실제로 그런 오류가 있었습니다. 2026년 10월 8일에 고친 알까기의 오류인데, 게임이 끝난 뒤에도 승패 처리 함수가 프레임마다 다시 불려 승리 횟수가 계속 오르고 효과음이 반복됐습니다. 승리 횟수를 랭킹으로 보내는 호출이 같은 자리에 있었으므로, 구조상 부풀려진 승수가 랭킹에 도달할 수 있었습니다. 서버는 개선된 점수만 받기 때문에 한 번 올라간 부풀린 숫자는 서버에서 스스로 낮아지지 않습니다. 코드를 고친 뒤에도 그 숫자가 이미 서버에 올라갔다면 남아 있게 됩니다. 이 사례에서 얻은 교훈은, 승수 같은 누적 값을 보내는 게임은 종료 처리가 한 번만 불리는지를 반드시 확인해야 한다는 것입니다.
카드가 뜨는 방식과 저장소가 막힌 환경
게임을 마치면 GameRank.report 한 줄로 점수를 보냅니다. 같은 접속에서 이미 보낸 기록보다 나아지지 않았다면 다시 보내지 않으므로(시간 기록은 더 작아야 함), 같은 점수가 반복 전송되지 않습니다. 닉네임이 있으면 자동으로 등록하고 오늘 순위 카드를 4.5초 동안 띄웁니다. 닉네임이 없으면 등록 카드를 15초 동안 띄우되, 60초 안에 다시 띄우지 않습니다. 경영 게임처럼 점수가 자주 갱신되는 게임은 조용한(quiet) 방식으로 순위 카드 없이 등록하고, 닉네임 안내도 접속당 한 번만 합니다.
닉네임은 gp:nick이라는 키로 브라우저에 저장됩니다. 시크릿 모드처럼 저장소 접근이 막힌 환경에서는 읽기와 쓰기가 모두 조용히 실패하도록 만들어 두었습니다. 게임이 멈추지는 않지만, 그 환경에서는 닉네임이 저장되지 않으므로 기록을 세울 때마다 닉네임을 다시 묻게 됩니다. 개발 중에는 scripts/smoke.js로 모든 게임을 저장소 차단 상태로도 열어서 콘솔 오류가 나지 않는지 점검합니다. 이 점검 덕분에 저장소가 막혀도 랭킹 카드와 게임이 정상적으로 열리는 것을 확인합니다.
이 구조에서 이용자께 부탁드리는 것
- 다른 사람이 쓰는 닉네임을 일부러 따라 쓰지 마세요. 소유권이 없는 구조라서, 같은 이름으로 올라간 기록은 하나로 합쳐집니다.
- 시간·횟수 기록은 숫자가 작을수록 좋습니다. 처음 보는 게임에서는 순위표의 단위(초, 번 만에)를 먼저 확인하세요.
- 3초 안에 연달아 등록 버튼을 누르면 잠시 후 다시 시도해 달라는 안내가 나옵니다. 기록이 사라진 것이 아니니 몇 초 뒤에 한 번만 다시 눌러 주세요.
- 정상 이름이 등록되지 않는다면 금칙어가 들어갔을 수 있습니다. 같은 글자를 피해 다른 이름을 써 주세요.
랭킹은 서로의 기록을 구경하며 가볍게 경쟁하는 자리이고, 지금 구조에서는 신뢰에 일부 기대고 있습니다. 서버가 막지 못하는 부분은 이용자 한 분 한 분이 정직하게 기록해 주실 때만 지켜집니다. 어색한 기록을 발견하셨다면 비난하기보다 사이트의 문의 페이지로 알려 주세요. 알려 주신 내용은 상한값을 조정하거나 규칙을 보완하는 근거가 됩니다.