AI 기반 패킷 이상 탐지로 스피드핵과 메모리 변조에 대응하는 서버 설계

멀티플레이 게임에서 클라이언트가 보낸 결과값을 서버가 그대로 받아들이면 상태 변조에 취약해질 수 있다. 서버 권위 검증과 Isolation Forest 기반 패킷 이상 탐지를 조합하는 설계 예시와 운영 시 확인할 점을 정리한다.

✓ 복사 완료!
챕터넷코드 & 상태 동기화 (Client Prediction/Lag)
난이도중급
상태● 검토 완료
대상 엔진
Engine Agnostic
최종 업데이트
AI 기반 패킷 이상 탐지로 스피드핵과 메모리 변조에 대응하는 서버 설계

게임 클라이언트에서 온 입력은 서버가 검증해야 한다. 한 가지 방어 설계는 서버가 이동·재화·전투의 권위 있는 상태를 계산하고, 정상 플레이에서 벗어난 패킷 특징을 이상 탐지 모델로 점수화하는 것이다. 모델 점수는 악의성의 증명이 아니므로 서버 규칙을 대신하지 않는 검토 신호로 다룬다.

스피드핵과 메모리 변조는 왜 발생하는가?

스피드핵은 클라이언트 시간이나 이동 관련 입력을 조작해 서버가 허용한 거리보다 빠르게 이동하려는 공격을 가리킬 수 있다. 메모리 변조로 클라이언트 값을 바꾸더라도 서버가 그 값을 권위 있는 결과로 받아들일 때 게임 상태에 영향을 줄 수 있다.

위험한 설계의 한 예는 서버가 position, hp, gold, cooldownEnd 같은 결과값을 검증 없이 받아들이는 것이다. 클라이언트는 move input, skill request, purchase request처럼 요청을 보내고, 서버가 권한·비용·쿨다운·충돌·게임 규칙을 검증한 뒤 상태를 갱신하도록 설계할 수 있다.

서버 권위 검증과 AI 이상 탐지 파이프라인을 설명하는 게임 네트워크 보안 구조

서버 권위 모델은 어떻게 구현할까?

먼저 서버 틱 기반 시뮬레이션을 만든다. 예를 들어 서버가 20Hz로 동작하면 한 틱의 시간은 0.05초다. 플레이어의 위치는 클라이언트가 보낸 절대 좌표가 아니라 서버가 보관한 위치와 입력값으로 계산한다.

1. 이동 가능 거리의 상한을 계산한다

서버가 처리하는 시뮬레이션 간격 Δt와 최대 이동 속도 v_max에서 한 구간의 최대 이동 거리를 다음처럼 계산할 수 있다. 패킷 도착 지연을 매 요청의 이동 거리 여유로 더하면 요청 빈도에 따라 이동량이 반복 가산될 수 있다. 지연 보정은 서버 리컨실리에이션 등 별도 정책으로 설계한다.

dmax=vmax×Δtd_{max}=v_{max}\times\Delta t

아래 예시는 방향 전용 입력을 버퍼링하고 권위 있는 시뮬레이션을 정해진 서버 틱마다 한 번 진행한다고 가정한다. 가속·아날로그 이동이 있다면 별도의 요청 속도/크기를 서버에서 제한한다. 순간이동 스킬은 일반 이동과 분리된 서버 승인 이벤트로 처리할 수 있다.

const TICK_SECONDS = 1 / 20;
const MAX_SPEED = 6.0;
function applyMove(player: Player, input: MoveInput) {
  // Direction-only input; call once per authoritative server tick.
  // Network packets update buffered input. Clamp any requested analog speed separately.
  const direction = normalizeOrZero(input.direction);
  const maxDistance = MAX_SPEED * TICK_SECONDS;
  const next = add(player.position, multiply(direction, maxDistance));

  if (!isWalkable(next) || !hasLineOfMovement(player.position, next)) {
    return rejectMove(player, "invalid_collision");
  }

  player.position = next;
}

위 예시에서 클라이언트는 방향만 전달하고 서버는 한 틱에 한 번만 이동을 계산한다. 더 반응성이 필요한 게임이라면 입력 시퀀스 번호와 클라이언트 틱을 함께 보내되 입력 순서와 재전송 방지에 활용하고, 이동 시간과 속도의 기준은 서버 시뮬레이션으로 유지한다.

2. 변조될 수 있는 상태값을 서버에서 소유한다

상태값클라이언트가 보내면 안 되는 값서버 검증 또는 계산 방식
위치최종 x, y, z입력, 속도, 충돌, 서버 틱으로 계산
체력피해 적용 후 HP서버가 공격 유효성 및 피해식을 계산
탄약남은 탄약 수서버가 발사 요청마다 차감
재화보유 골드서버 트랜잭션으로 증감
쿨다운스킬 사용 가능 여부서버의 cooldownEnd와 현재 시각 비교

재화와 인벤토리 변경은 데이터베이스 트랜잭션으로 묶어 처리하는 방식을 고려한다. UPDATE ... SET gold = gold - :cost WHERE player_id = :id AND gold >= :cost 같은 조건부 갱신은 잔액이 충분한 행만 차감한다. 실제 구매에서는 영향받은 행 수를 확인하고 재화 차감과 아이템 지급을 같은 트랜잭션에 넣어야 한다. :cost, :id는 드라이버에 맞춰 바인딩할 매개변수 표기 예시다.

3. 패킷 재전송과 순서 조작을 차단한다

각 입력에 연결 단위로 증가하는 sequence를 포함하고 서버는 이미 처리한 중복·오래된 패킷을 정책에 따라 거부할 수 있다. 순번 초기화와 정수 범위 순환은 연결 프로토콜에서 별도로 처리한다. 중요한 구매·보상 요청은 사용자와 작업 종류에 범위를 둔 idempotencyKey에 고유 제약을 걸고 결과를 저장해, 같은 키의 재전송이 효과를 반복하지 않게 설계한다. TLS/DTLS는 전송 구간의 기밀성과 변조 탐지를 제공할 수 있지만, 악성 클라이언트가 보낸 유효한 형식의 요청을 검증하지는 않는다.

AI 패킷 이상 탐지는 무엇을 보는가?

규칙 기반 검증은 명확한 위반을 빠르게 차단한다. 하지만 속도를 한계 바로 아래로 유지하거나 패킷 빈도만 미세하게 조절하는 공격은 단일 규칙으로 놓칠 수 있다. 이때 플레이어별 시간 창에서 만든 특징 벡터를 이상 탐지 모델에 입력한다.

관측 창을 30초, 갱신 주기를 5초로 두면 다음과 같은 특징을 사용할 수 있다.

  • move_distance_per_second: 초당 서버 승인 이동 거리
  • input_packets_per_second: 초당 이동 입력 패킷 수
  • sequence_gap_rate: 누락 또는 비정상 순번 비율
  • rejected_move_rate: 충돌·거리 검증 거부 비율
  • rtt_median_ms, rtt_p95_ms: 지연 분포
  • cooldown_violation_count: 쿨다운 위반 요청 수
  • economy_delta_zscore: 동일 레벨·콘텐츠 집단 대비 재화 변동 점수

거리 기반 특징은 맵, 탈것, 버프에 따라 달라진다. 따라서 원시 이동 거리를 그대로 모델에 넣기보다 허용 속도로 정규화한 값을 쓴다.

speedRatio=dobservedvallowed×Δt+εspeedRatio=\frac{d_{observed}}{v_{allowed}\times\Delta t+\varepsilon}

speedRatio가 1보다 크면 규칙 위반 후보지만 실제 제재 전에 순간이동 스킬, 서버 지연, 리스폰, 컷신 같은 합법 이벤트를 제외해야 한다.

Isolation Forest로 패킷 이상 탐지를 구현하는 방법

Isolation Forest는 무작위 분할 트리에서 짧은 경로로 분리되는 관측치에 낮은 점수를 주는 비지도 이상 탐지 알고리즘이다. 라벨이 부족한 상황에서 후보 모델로 시험할 수 있지만, 정상 데이터의 대표성·특징·오탐 비용에 따라 성능이 달라지므로 운영 적합성을 검증해야 한다.

1. 로그 스키마와 특징 저장소를 분리한다

원본 패킷 전체를 장기간 저장하면 저장 비용과 데이터 노출 범위가 커질 수 있다. 보안 분석에 필요한 이벤트와 집계 특징을 분리해 보관하는 방식을 검토한다.

-- PostgreSQL schema example; adapt types and bindings to the database/driver.
CREATE TABLE player_security_window (
  window_start       timestamptz NOT NULL,
  player_id          uuid        NOT NULL,
  move_meters        real        NOT NULL,
  input_count        integer     NOT NULL,
  rejected_count     integer     NOT NULL,
  sequence_gap_count integer     NOT NULL,
  rtt_median_ms      real,
  cooldown_violations integer    NOT NULL,
  PRIMARY KEY (window_start, player_id)
);

보안 이벤트에는 분석에 필요한 식별자와 필드만 두고, 보존 기간과 접근 권한을 정한다. 계정 ID를 해시해도 다른 정보와 결합해 재식별될 가능성이 있으므로 내부 접근 통제와 데이터 최소화를 함께 검토한다.

2. 정상 플레이 데이터로 학습한다

학습 데이터에는 이미 제재된 계정, QA 봇, 관리자 명령을 사용한 계정, 대규모 서버 장애 시간대를 제외한다. 모드·맵·캐릭터·이동 버프가 다르면 별도 모델 또는 조건별 특징 정규화가 필요하다.

Python과 scikit-learn 예시는 다음과 같다.

from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import RobustScaler

features = [
    "speed_ratio_p95",
    "input_packets_per_second",
    "rejected_move_rate",
    "sequence_gap_rate",
    "cooldown_violation_count",
]

scaler = RobustScaler()
X = scaler.fit_transform(normal_windows[features])

model = IsolationForest(
    n_estimators=300,
    max_samples="auto",
    contamination=0.002,
    random_state=42,
    n_jobs=-1,
)
model.fit(X)

# predict: -1은 이상, 1은 정상. score_samples가 작을수록 더 이상하다.
score = model.score_samples(scaler.transform(current_window[features]))

contamination=0.002는 학습 데이터에서 이상치 비율을 가정해 결정 경계(threshold)를 정하는 설정이지, 실제 운영 창 중 정확히 0.2%가 탐지된다는 보장은 아니다. 실제 값은 검토 인력, 플레이어 분포, 오탐 비용을 고려해 검증 데이터에서 조정한다. 정상 데이터 학습 집합에 공격 사례가 섞이면 기준이 달라질 수 있으므로 검토 결과도 추적한다.

3. 모델 점수와 규칙 점수를 결합한다

모델의 원시 score_samples는 확률이 아니며 값이 낮을수록 더 이상한 관측치다. 운영에서는 검증 데이터를 기준으로 순위를 반전하거나 정규화해 0~1 범위의 anomalySeverity 입력 특징으로 바꿀 수 있다. 이 변환 결과 역시 제재 확률이 아니다. 가중치와 임계값은 별도 검증을 거친 뒤 모델 점수·규칙·최근 이력으로 대응 단계를 나눈다.

function securityAction(event: SecurityEvent): SecurityAction {
  if (event.teleportWithoutServerEvent || event.goldMutationMismatch) {
    return "block_and_review";
  }

  // Illustrative weights and thresholds; validate against reviewed cases before use.
  const risk =
  0.55 * event.anomalySeverity +
    0.25 * Math.min(event.rejectedMoveRate * 4, 1) +
    0.20 * Math.min(event.cooldownViolationCount / 3, 1);

  if (risk >= 0.85) return "shadow_restrict_and_review";
  if (risk >= 0.65) return "increase_sampling";
  return "allow";
}

위험 점수는 계정 단위로 지수 이동 평균을 적용해 일시적인 네트워크 흔들림보다 반복 패턴에 민감하게 만든다.

Rt=αrt+(1−α)Rt−1R_t=\alpha r_t+(1-\alpha)R_{t-1}

여기서 r_t는 현재 창의 위험 점수이며 α는 0.2~0.4 범위에서 게임의 매치 길이에 맞춰 조정할 수 있다.

flowchart LR
  A[클라이언트 입력 패킷] --> B[서버 권위 규칙 검증]
  B -->|허용| C[서버 상태 갱신]
  B -->|위반| D[즉시 차단 및 이벤트 기록]
  C --> E[30초 특징 집계]
  D --> E
  E --> F[Isolation Forest 점수]
  F --> G[위험 점수 결합]
  G --> H[허용·추가 관측·검토·제한]

스피드핵 탐지 임계값은 어떻게 정할까?

임계값은 게임 규칙과 오탐 비용에 맞춰 검증한다. 다음은 한 가지 운영 절차다.

  1. 하드 한계를 정의한다. 서버가 계산한 최대 거리, 쿨다운, 재화 잔액처럼 물리적·경제적으로 불가능한 값은 즉시 거부한다.
  2. 정상 기준선을 수집한다. 지역, 플랫폼, 맵, 이동 버프를 대표하는 충분한 기간의 정상 분포를 수집하고 중앙값과 P95·P99를 기록한다. 예를 들어 시작 수집 기간을 며칠로 둘 수 있지만, 계절성·주간 이벤트·플레이 규모를 포함하는지는 프로젝트에 따라 결정한다.
  3. 검토 가능한 후보량으로 조정한다. 이상 점수 임계값을 바꿔 일일 탐지량, 실제 위반 비율, 오탐률을 측정한다. 먼저 추가 로그 수집과 매치메이킹 분리를 적용하고 검토 근거가 쌓인 계정에만 강한 제재를 적용한다.

모바일 네트워크에서도 패킷 도착 간격과 지연이 흔들릴 수 있다. 패킷 도착 간격만으로 스피드핵을 판정하지 말고 서버가 승인한 이동 거리와 서버 시뮬레이션 시간의 관계를 우선 검증한다.

운영에서 반드시 확인할 지표

지표의미경고 신호
차단률하드 규칙으로 거부된 요청 비율배포 직후 급증하면 정상 기능 회귀 가능성
이상 후보율모델이 후보로 분류한 플레이어 창 비율모델 드리프트 또는 신규 공격 가능성
검토 확정률검토 후 실제 위반으로 확인된 비율낮으면 임계값 또는 특징 개선 필요
오탐 이의 제기율제재 후 정상 사용자로 판명된 비율자동 제재 강도가 과도하다는 신호
특징 결측률모델 입력값 누락 비율텔레메트리 파이프라인 장애 신호

모델 버전, 특징 스키마 버전, 임계값, 판정 근거를 모든 제재 이벤트에 함께 기록한다. 그래야 업데이트 뒤 탐지율 변화와 잘못된 제재를 재현할 수 있다.

자주 묻는 질문 (FAQ)

클라이언트 안티치트만으로 스피드핵을 막을 수 있나?

아니다. 클라이언트 안티치트는 변조 비용을 높이는 보조 수단이다. 최종 방어선은 서버 권위 이동 계산과 서버 시간 기반 검증이어야 한다.

Isolation Forest가 치터를 자동으로 확정해도 되나?

권장하지 않는다. Isolation Forest는 정상 패턴과 다른 행동을 찾을 뿐, 악의성을 증명하지는 못한다. 하드 규칙, 반복 이력, 검토 로그와 결합해 대응 단계를 결정해야 한다.

암호화된 TLS 패킷도 이상 탐지가 가능한가?

가능하다. 서버가 복호화한 뒤 패킷 내용 또는 집계 특징을 분석한다. 전송 암호화는 제3자의 도청·변조를 막지만 조작된 클라이언트가 보낸 합법 형식 요청은 막지 못한다.

참고 자료

정리

스피드핵과 메모리 변조 방어에서 서버 검증 규칙은 권위 있는 상태와 요청을 판정하고, Isolation Forest 같은 이상 탐지 모델은 검토 후보를 추가할 수 있다. 모델 효과와 대응 단계는 오탐·미탐 평가와 운영 검토를 거쳐 결정한다.