--- type: 기획서 project: 수상한잡화점 version: v1 status: 진행중 author: 기획팀장 date: 2026-04-17 scope: 어뷰징 판정 프레임워크 (설계 원칙 + 스키마 + 예시 틀) related_rules: [C7, C11, C13, C23, P23] related_docs: - 공유/소통/기획팀→PM/2026-04-17_Unity_MCP_시뮬레이션_기획검토_기획팀.md - 프로젝트/수상한잡화점/기획/Phase3_재개준비_체크리스트_v1.md --- # 어뷰징 판정 솔루션 기획서 v1 ## 요지 스테이지 클리어 보상·랭킹 등록·일일 미션에서 클라가 전송하는 데이터를 서버가 **"시뮬레이터 산정 이론 상한 경계값"** 기반으로 검증하여, 경계를 초과하는 요청을 어뷰저로 판정·차단한다. 기획팀은 경계값 도출 방법론과 테이블 스키마를 제공하고, 서버는 검증 로직을 탑재한다. 실제 수치는 Unity MCP 시뮬 가동 결과로 채워진다(본 기획서는 틀만 제공). **재미 관점(C7)**: 어뷰징이 방치되면 랭킹·미션의 도전 가치가 붕괴되고, 정상 플레이어의 성취감이 훼손된다. 본 솔루션의 목표는 "정직한 플레이어의 재미를 보호"하는 것이지 선의의 실력자를 잡는 것이 아니다. 따라서 경계값은 **이론 상한에 안전 마진을 더한 값**으로 설정하여 false positive를 최소화한다. --- ## A. 문제 정의 ### A-1. 전제 - 모든 보상(미션·스테이지·랭킹) = 재화 형태로 지급 확정 (2026-04-17 PD님 결정) - 스테이지 클리어·랭킹 등록에서 서버는 클라 전송 데이터를 기반으로 보상을 산정/기록한다 - 클라를 무조건 신뢰하면 메모리 조작·패킷 위변조를 통한 재화 부당 획득이 가능하다 ### A-2. 어뷰징 공격 벡터 | 벡터 ID | 대상 액션 | 조작 포인트 | 파급 위험 | |--------|----------|-----------|---------| | **AV-1** | 스테이지 클리어 완료 패킷 | 클리어타임 단축 (예: 0초·음수) | 시간 가속 보상 파밍 | | **AV-2** | 스테이지 클리어 완료 패킷 | 획득 재화량 조작 (상한 초과) | 재화 무한 생성 | | **AV-3** | 스테이지 클리어 완료 패킷 | 별(★) 개수 조작 (3/3 고정) | 미달성 보상 부당 수령 | | **AV-4** | 스테이지 클리어 완료 패킷 | 소모 자원 0 보고 (물약·쉴드·HP) | ★조건 달성 위조 (C6 포션절제, N2 피격제한 등) | | **AV-5** | 랭킹 등록 패킷 | 점수값 조작 (이론 상한 초과) | 랭킹 1위 탈취 | | **AV-6** | 랭킹 등록 패킷 | 연관 메타값 조작 (사용 카드·편성 등 검증 소재) | 검증 회피 | | **AV-7** | 일일 미션 카운트 | 카운트 중복 전송·상한 초과 | 일일 한도 초과 보상 수령 | | **AV-8** | 리플레이/재접속 재전송 | 동일 클리어 결과 재제출 | 중복 보상 | | **AV-9** | 스테이지 잠금 우회 | 언락 안 된 스테이지 완료 패킷 | 진행도 건너뛰기 | ### A-3. 판정 대상 범주 3종 1. **물리적 불가능** — 시뮬레이터로도 달성 불가능한 수치 (예: 클리어타임 0초, 점수 int.MaxValue) 2. **확률적 극단** — 이론상 가능하나 확률이 충분히 낮아 사실상 어뷰징으로 간주 (예: 운으로 1회 나올 수치의 연속 달성) 3. **논리적 모순** — 내부 값들이 서로 모순 (예: "피격 0회"인데 "HP 50% 소진") --- ## B. 경계값 도출 방법론 ### B-1. 기본 공식 ``` 경계값 = 시뮬_이론_극값 × 안전마진계수 ``` - `시뮬_이론_극값`: Unity MCP 시뮬을 N회(권장 N=1,000 이상) 수행하여 얻은 **최상위 극값** (최대/최소는 벡터에 따라 다름) - `안전마진계수`: 벡터 특성에 따라 결정하는 완화 계수 (정상 플레이어 오차 허용) ### B-2. 안전마진 설계 원칙 | 벡터 특성 | 마진 방향 | 계수 예시 | 근거 | |---------|--------|---------|------| | 클리어타임 (짧을수록 의심) | 하한 경계값 = 이론 최단 × **0.80** | 0.80 | 프레임 드랍·클라 시계 오차로 정상 유저도 5~15% 짧게 보고 가능 | | 획득 재화 (많을수록 의심) | 상한 경계값 = 이론 최대 × **1.05** | 1.05 | 소숫점 반올림·버프 중첩 경계 케이스 흡수 | | 랭킹 점수 (높을수록 의심) | 상한 경계값 = 이론 최대 × **1.10** | 1.10 | 신규 카드 출시 등 업데이트 이후 시뮬 갱신 전 과도기 흡수 | | 피격 수 (적을수록 의심) | 하한 경계값 = 이론 최소 (= 0) | - | 0회도 이론상 가능, 음수만 차단 | | 미션 카운트 | 상한 경계값 = 일일 최대 달성 가능치 × **1.00** | 1.00 | 마진 불필요 (정수 카운트) | **주의**: 마진은 "정상 유저를 어뷰저로 오판정하지 않기 위한" 안전장치지, "어뷰저를 놓치는 관용"이 아니다. 극값의 80%~110% 범위는 경계이므로 이 범위 유저는 "**1차 통과 + 플래그 미부여**"로 처리한다. ### B-3. 업데이트 주기 1. **정기 갱신**: 밸런스 패치(카드 수치 변경·신규 몬스터 추가) 시 해당 영역 시뮬 재실행 2. **긴급 갱신**: 어뷰징 신고 접수 또는 랭킹 이상치 감지 시 즉시 시뮬 재실행·경계값 조정 3. **버전 관리**: 경계값 테이블은 C6에 따라 `.bak_{YYYYMMDD_HHMM}.json` 백업 후 교체 4. **C13 기록**: 경계값 변경은 PD 지시 로그·대화로그에 기각안 포함 기록 (P24) ### B-4. 시뮬레이터 입력 조건 (Unity MCP) 각 스테이지·각 벡터에 대해 다음 조건의 최극단 조합을 시뮬: - 캐릭터: 최강 편성 (풀레벨·최적 카드) - 적 패턴: 최선 운 (치명타 확률 최대·적 회피 최소) - 플레이 입력: 완벽 입력 (반응시간 0·공백 없음) - 물약·쉴드: 최대 활용 (획득 재화 벡터) / 미사용 (C6 조건 벡터) **출력 수집**: 10,000회 반복하여 상위/하위 0.1% 값을 "이론 극값"으로 채택 (절대 최대/최소 아닌 이유 = 시뮬 자체 오차 흡수). --- ## C. 검증 계층 설계 ### C-1. 2계층 검증 원칙 **1계층 (클라)** — 예방적 차단 - 목적: 악의적 조작이 아닌 **버그·의도치 않은 극값**을 클라 단에서 거르기 - 클라가 자체 생성한 결과값이 경계값을 초과하면 전송 보류 + 경고 로그 수집 - **클라 신뢰는 하지 않음** — 이 계층만으로는 판정 금지 (메모리 조작 시 이 계층 무력화 가능) **2계층 (서버)** — 최종 판정 - 목적: 모든 어뷰징 판정의 **단일 결정권자** - 서버가 경계값 테이블을 보유하고 수신 패킷 전량 검증 - 경계 초과 시: 거부 + 플래그 기록 + (심각도에 따라) 관리자 알림 ### C-2. 검증 흐름 (서버) ``` [클라 패킷 수신] ↓ [Step 1] 기본 유효성 (음수·null·형식 오류) → 거부 ↓ [Step 2] 스테이지 잠금 상태 확인 (AV-9 대응) → 거부 ↓ [Step 3] 중복 제출 확인 (AV-8 대응, 같은 세션ID·클리어ID) → 거부 ↓ [Step 4] 경계값 테이블 조회 → 각 필드 범위 검증 ↓ (통과) [Step 5] 논리 정합성 검증 (필드 간 모순, A-3-3 범주) ↓ (통과) [정상 처리 + 보상 지급] ↓ (Step 4·5 실패 시) [플래그 기록 + 보상 보류 + 심각도별 조치] ``` ### C-3. 역할 분담 원칙 | 주체 | 역할 | 금지 | |-----|-----|-----| | 클라 | 버그 조기 감지·UX 경고 | 최종 판정, 플래그 기록 | | 서버 | 최종 판정, 플래그 DB 기록, 관리자 알림 | 클라 통과 가정·검증 생략 | | 기획팀 | 경계값 테이블 공급 | 서버 검증 로직 직접 작성 | | 인간 서버 개발자 | 검증 로직 구현·플래그 DB 스키마 | 경계값 자체 수정 (기획 승인 없이) | --- ## D. 어뷰저 플래그 체계 ### D-1. 플래그 종류 3단계 | 단계 | 트리거 | 자동 조치 | 관리자 조치 | |-----|-------|---------|-----------| | **F1 경미** | 경계값의 +5%~+10% 범위 이내 초과 (마진 범위 경계) | 플래그 기록만 | 누적 3회 이상 시 F2 격상 | | **F2 중대** | 경계값의 +10%~+50% 초과, 또는 F1 3회 누적 | 해당 보상 보류 + 관리자 알림 | 수동 검토 후 재화 회수·경고 | | **F3 확정** | 경계값의 +50% 초과, 논리 모순 발생, 또는 F2 2회 누적 | 해당 보상 미지급 + 계정 플래그 | 계정 정지 검토 (랭킹 삭제 포함) | ### D-2. 플래그 누적 처리 - 플래그 DB: `{user_id, timestamp, vector_id, flag_level, raw_data, boundary_value, reason}` - 기간 윈도우: 최근 30일 기준 누적 (기획팀 권고안, 서버측 조정 가능) - 에스컬레이션: F1×3 → F2 / F2×2 → F3 / F3×1 → 즉시 계정 정지 검토 대상 ### D-3. 기획팀 권고안 (PM 경유 운영팀 협의 필요) - **F1**: 자동 회수 없음 (false positive 위험). 사용자에게 경고도 노출하지 않음 (어뷰저 학습 방지) - **F2**: 해당 회차 보상만 회수. 사용자에게는 "서버 동기화 오류, 재시도" 메시지 노출 - **F3**: 계정 정지는 관리자 최종 판단. 랭킹 등록 데이터는 즉시 삭제 --- ## E. 대상 액션별 구체 경계값 초안 > **주의**: 아래 수치는 모두 **플레이스홀더**. Unity MCP 시뮬 가동 후 확정. 실제 경계값 테이블은 별도 JSON으로 관리. ### E-1. 스테이지 클리어 | 필드 | 검증 규칙 | 경계값 예시 (Stage 1) | |-----|---------|----------------------| | `clearTime` | `sim_min × 0.80` 하한, `sim_max × 1.20` 상한 | 하한: 미확정(시뮬 후) / 상한: 미확정 | | `goldEarned` | `sim_max × 1.05` 상한 | 상한: 미확정(시뮬 후) | | `starsEarned` | 0~3 정수, ★조건 메타값과 교차 검증 | 0~3 | | `hpRemaining` | `0 ≤ hp ≤ maxHp` | 캐릭터 maxHp 기반 | | `potionUsed` | 0 이상 정수, 소지 한도 이하 | 캐릭터 포션 한도 | | `shieldRemaining` | `0 ≤ shield ≤ maxShield` | 캐릭터 maxShield 기반 | | `hitsTaken` | 0 이상 정수, `sim_max × 1.20` 상한 | 상한: 미확정(시뮬 후) | ### E-2. 랭킹 등록 | 필드 | 검증 규칙 | 경계값 예시 | |-----|---------|----------| | `score` | `sim_max × 1.10` 상한 | 상한: 미확정(시뮬 후) | | `clearTime` | 동일 스테이지 E-1 규칙 적용 | - | | `deckComposition` | 소유 카드 목록과 교차 검증 | - | | `stageId` | 유효 스테이지 ID (잠금 해제 상태) | - | ### E-3. 일일 미션 | 필드 | 검증 규칙 | 경계값 예시 | |-----|---------|----------| | `missionId` | 유효 미션 ID + 당일 활성 | - | | `currentCount` | `missionMaxCount` 상한 | 미션별 상한 | | `incrementDelta` | 단일 트리거로 1 증가만 허용 | 1 | | `completionTimestamp` | 일일 리셋 시각 이후 ~ 현재 | - | ### E-4. ★조건 교차 검증 (P17 연계) 각 스테이지의 활성 ★조건(C1~C9, N1~N6)과 클리어 결과 필드가 정합해야 한다. 예: - **C6 (포션 절제)**: `potionUsed == 0` 인지 확인 - **N2 (피격 제한)**: `hitsTaken ≤ 서브맵수 × 1` 인지 확인 - **N4 (쉴드 하한 30%)**: `shieldRemaining ≥ maxShield × 0.30` 인지 확인 ★조건 통과 보고와 필드 값이 모순되면 **F3 확정 플래그** (논리 모순). --- ## F. 서버 측 요구사항 (개발팀 인계용) ### F-1. 기획팀 공급 산출물 1. **경계값 테이블** — JSON 파일 (Unity MCP 시뮬 결과 반영) 2. **★조건 검증 규칙** — 스테이지별 활성 조건 + 판정 로직 3. **플래그 기준** — F1/F2/F3 경계 정의 4. **갱신 공지** — 경계값 변경 시 개발팀에 PR 또는 소통 채널 통지 ### F-2. 경계값 테이블 스키마 (JSON 예시) ```json { "version": "1.0.0", "generatedAt": "2026-04-17T00:00:00Z", "simulationRuns": 10000, "stages": { "stage_01": { "clearTime": { "min": 42.3, "max": 180.0, "marginLow": 0.80, "marginHigh": 1.20, "boundaryMin": 33.84, "boundaryMax": 216.0 }, "goldEarned": { "max": 250, "marginHigh": 1.05, "boundaryMax": 263 }, "hitsTaken": { "min": 0, "max": 8, "marginHigh": 1.20, "boundaryMax": 10 }, "starConditions": { "C2": { "field": "hitsTaken", "operator": "==", "value": 0 }, "C6": { "field": "potionUsed", "operator": "==", "value": 0 }, "N2": { "field": "hitsTaken", "operator": "<=", "formula": "subMapCount * 1" } } } }, "ranking": { "stage_01": { "score": { "max": 12500, "marginHigh": 1.10, "boundaryMax": 13750 } } }, "dailyMissions": { "login": { "maxCount": 1 }, "clear_any_stage": { "maxCount": 10 } } } ``` ### F-3. 검증 API 호출 흐름 (서버 내부) ``` 수신: POST /api/stage/complete body: { userId, stageId, clearTime, goldEarned, starsEarned, hitsTaken, potionUsed, ... } 서버 처리: 1. AbuseValidator.validate(userId, stageId, body) → boundaries = BoundaryTable.get(stageId) → for each field: 경계값 비교 → starCondition 교차 검증 → 중복 제출 체크 2. ValidationResult: - PASS: 보상 지급 처리 - F1: 보상 지급 + 플래그 기록 - F2: 보상 보류 + 플래그 기록 + 관리자 알림 - F3: 보상 미지급 + 플래그 기록 + 계정 플래그 3. 응답: - PASS/F1: { status: "success", rewards: [...] } - F2: { status: "pending", message: "서버 동기화 오류, 재시도 바랍니다" } - F3: { status: "blocked" } (어뷰저 학습 방지 위해 구체 사유 미노출) ``` ### F-4. 위반 응답 포맷 (권고) 어뷰저 학습 방지를 위해 구체 수치·사유를 클라에 노출하지 않는다: ```json // F1 (경미) { "status": "success", "rewards": [...] } // 플래그는 서버 내부만, 클라 무감지 // F2 (중대) { "status": "pending", "message": "서버 동기화 오류, 잠시 후 재시도" } // F3 (확정) { "status": "blocked" } ``` ### F-5. 플래그 DB 스키마 (서버 구현 시 참조) ``` AbuseFlag: - id: UUID - userId: string - timestamp: datetime - vectorId: enum (AV-1 ~ AV-9) - flagLevel: enum (F1, F2, F3) - stageId: string (nullable) - fieldName: string - rawValue: json - boundaryValue: json - exceedRate: float // (rawValue - boundary) / boundary - reason: string - reviewedBy: string (nullable) - reviewedAt: datetime (nullable) - resolution: enum (pending, confirmed_abuse, false_positive, pardoned) ``` --- ## G. 기각안 ### G-1. 서버 단독 시뮬 재현 검증 (채택 안 함) - **안**: 서버가 클라 입력(키·타이밍)을 받아 서버에서 전투를 재시뮬하여 결과 일치 여부 검증 - **기각 사유**: (1) 서버 CPU 비용 폭증 — 1회 재시뮬 ≈ 1개 전투 전체 연산 (2) 동기화 이슈 (난수 시드·부동소수점) (3) 현 프로젝트가 실시간 멀티플레이가 아닌 싱글 플레이 구조라 과잉 투자. **채택 안**인 "경계값 기반 통계적 검증"이 비용·구현 난이도·효과 3축에서 우수. ### G-2. 머신러닝 기반 이상치 탐지 (채택 안 함) - **안**: 유저 플레이 데이터를 수집하여 ML 모델로 어뷰저 이상치 자동 탐지 - **기각 사유**: (1) 학습 데이터 축적에 운영 기간 필요 — 초기 출시 대응 불가 (2) false positive 조정 난해 (3) 인간 서버 개발자 부담 가중. 장기적 보조 수단으로는 고려 가치 있으나 v1 범위에서 제외. 본 기획서는 시뮬 경계값으로 출시 대응 + 운영 후 데이터 축적 → 차후 ML 도입 여지 유지. ### G-3. 클라 단독 판정 (채택 안 함) - **안**: 클라가 자체 검증 후 서버에는 결과만 전송 - **기각 사유**: 메모리 조작·패킷 위변조로 무력화됨. 어뷰징 방지 근본 목적 미달성. **원천적으로 고려 대상 아님**. ### G-4. 전체 플레이 로그 전송·서버 기록 (채택 안 함) - **안**: 매 프레임 입력 로그 전체를 서버로 전송하여 서버가 사후 감사 - **기각 사유**: (1) 네트워크 비용 과도 (2) 저장소 비용 (3) G-1과 유사하게 오버엔지니어링. F3 확정 플래그 시점에 사후 감사용으로 마지막 30초~60초 정도만 보관하는 방안은 서버측 재량. ### G-5. 안전 마진 0% 엄격 검증 (채택 안 함) - **안**: 시뮬 극값을 그대로 경계값으로 사용하여 극한 배제 - **기각 사유**: false positive 폭발. 프레임 드랍·반올림 오차로 정상 유저도 매번 플래그됨. **C7 재미 우선 원칙 위반** — 정상 플레이어 경험 훼손. 5%~20% 마진 보정 필수. --- ## 후속 작업 (Unity MCP 시뮬 가동 후 수행) 1. 각 스테이지·각 벡터별 시뮬 10,000회 실행 2. 경계값 테이블 JSON 1차 산출 (v1.0.0) 3. balance-designer 검토 → 재미 관점 마진 재조정 4. 개발팀과 스키마·API 계약 확정 (`공유/소통/기획팀→개발팀/` 발행) 5. 플래그 DB 스키마 서버팀 리뷰·구현 6. 통합 QA 시 어뷰저 시뮬 툴로 F1/F2/F3 각각 검증 케이스 생성 ## 연관 규칙·문서 - **C7**: 재미 우선 — 정상 플레이어 보호를 위한 마진 설계 근거 - **C11**: 개발 관점 — 서버 자원 효율 고려하여 재시뮬 대신 경계값 비교 채택 (G-1 기각 근거) - **C13**: PD 지시 트래킹 — 본 기획 등록 및 경계값 변경 이력 관리 - **C23**: 허위 보고 금지 — 본 기획서는 실제 시뮬 가동 전이므로 수치는 모두 플레이스홀더 명시 - **P17**: ★조건 배타 배치 — E-4 ★조건 교차 검증과 연계 - **P23**: 기획 결정 재량 — 본 기획은 기획팀장 재량 범위(신규 시스템 제안은 PM 확인 필요 → 본 기획서 발행으로 PM 확인 경유) --- **기획팀장 발의** **PM 검토 요청**: 본 기획서 스키마·프레임워크 승인 → 개발팀 F 섹션 인계 트리거 **승인 후 착수**: Unity MCP 시뮬 가동 (별도 PD 지시 로그)