Arhitectură anti-cheat: autoritate server și analiză comportamentală
Trișarea în jocurile video reprezintă o problemă de 30 de miliarde de dolari pe an pentru industria jocurilor de noroc. Nu totul ține de corectitudine: trișorii distrug experiența altor jucători, cresc abandonează, reduce veniturile și dăunează reputației jocului. Un sondaj din 2024 are a constatat că 77% dintre jucători au abandonat un titlu multiplayer din cauza trișorilor.
Soluțiile tradiționale anti-cheat - Valve's VAC, Easy Anti-Cheat, BattlEye - se bazează în principal despre detecție pe partea clientului: un driver care monitorizează procesele sistem de operare pentru a detecta trucurile software. Această abordare are o problemă fundamentală: și un joc de pisică și șoarece care trișatorii câștigă constant pe hardware personalizat, hipervizor și bypass de kernel. Contramăsura modernă șiarhitectură cu autoritate de server combinat cu analiză comportamentală ML.
În acest articol vom explora o arhitectură completă anti-cheat: de la serverul autoritar care validează fiecare acțiune, la validarea statistică a valorii aberante, la sistemele bazate pe ML transformator pentru detectarea comportamentală (precizie 96,94%, AUC 98,36% în căutări 2025).
Ce vei învăța
- Tipuri de trucuri: speed hack, target bot, wall hack, ESP, exploatare economică
- Arhitectură cu autoritate de server: ce să delegați clientului și ce nu
- Validare pe partea serverului: fizică, detectarea coliziunilor, linia vizuală
- Detectarea valorii aberante statistice: scor Z, k-sigma pentru analiza obiectivului
- Analiză comportamentală ML: inginerie de caracteristici pentru anti-cheat
- Detectare cheat pe bază de transformator (abordare AntiCheatPT)
- Analiza reluării: detectare post-hoc prin telemetrie
- Management fals pozitiv: protejarea jucătorilor nevinovați
1. Cheat Taxonomie: Contra ce lupți
Înainte de a proiecta apărările, este esențial să înțelegem ce trebuie contracarat. Trucuri sunt împărțite în două macro-categorii: cele care modifică comportamentul clientului (manipularea intrărilor) și cele care exploatează vulnerabilități în protocolul sau logica jocului (exploatarea protocolului).
Trucuri de taxonomie și contramăsuri
| Trucuri | Descriere | Detectare | Prevenirea |
|---|---|---|---|
| Speed Hack | Schimbați ceasul sistemului pentru a vă deplasa mai repede | Server de verificare a vitezei | Fizica cu autoritate de server |
| Teleport Hack | Setați poziția arbitrară, săriți validarea mișcării | Verificare delta poziționării | Poziție cu autoritate de server |
| Aim Bot | Țintește automat jucătorii cu o acuratețe supraomenească | Analiza scopului statistic | Detectarea comportamentală ML |
| Hack de perete / ESP | El vede jucătorii prin pereți | Taierea frustum pe partea serverului | Nu trimite locații inamice nevăzute |
| Fără recul | Elimină recul pentru a trage cu precizie constantă | Analiza modelului de tragere | Simulare de recul pe partea serverului |
| Exploatare economică | Duplicați monedă sau articole prin condiția de cursă | Auditul tranzacțiilor | Tranzacții idempotente + limitarea ratei |
| Manipularea pachetelor | Modificați pachetele de rețea pentru a modifica starea jocului | Validarea mesajului | DTLS/TLS + validare schema |
2. Arhitectură cu autoritate de server: Fundamentul securității
Principiul cheie al anti-cheat-ului modern este: serverul este sursa adevărului absolut. Clientul trimite doar intrare (ce vrea jucătorul să facă), niciodată rezultatele (ce s-a întâmplat). Serverul calculează starea jocului și o comunică clienților. Acest lucru elimină categoric hack-urile de viteză, hack-urile de teleportare, exploatările economice și hack-urile de perete de pachete.
// Server-Authoritative Game Loop - Go
// Il server calcola TUTTO: posizione, danno, risultati
type AuthoritativeServer struct {
players map[string]*PlayerState
world *WorldState
physics *PhysicsEngine // Server-side physics simulation
lineOfSight *LOSCalculator // Calcolo visibilità server-side
}
// ProcessInput: l'unica cosa che il client invia e l'input
// Il server valida e calcola il risultato
func (s *AuthoritativeServer) ProcessInput(playerID string, input PlayerInput) *GameStateUpdate {
player, ok := s.players[playerID]
if !ok {
return nil
}
// === VALIDAZIONE INPUT ===
// 1. Rate limiting: un player non può inviare input più di N/tick
if !s.rateLimiter.Allow(playerID) {
return &GameStateUpdate{Error: "input_rate_exceeded"}
}
// 2. Validazione movimento: fisica server-side
if input.Type == InputTypeMove {
newPos := player.Position.Add(input.MoveDelta)
// Verifica velocità massima (impossibile con speed hack se server calcola)
maxSpeed := player.GetMaxSpeed() // Dipende da buff, terreno, etc.
actualSpeed := input.MoveDelta.Length() / s.tickDeltaTime
if actualSpeed > maxSpeed*1.1 { // 10% tolerance per jitter di rete
s.flagSuspicious(playerID, "speed_violation",
fmt.Sprintf("speed=%.2f max=%.2f", actualSpeed, maxSpeed))
return &GameStateUpdate{Position: player.Position} // Ignora il movimento
}
// Verifica collisioni server-side
if !s.world.IsPositionValid(newPos, player.Size) {
s.flagSuspicious(playerID, "wall_clip_attempt",
fmt.Sprintf("pos=%v", newPos))
return &GameStateUpdate{Position: player.Position}
}
// Aggiorna posizione SOLO dopo validazione
player.Position = newPos
}
// 3. Validazione attacco: server-side hit detection
if input.Type == InputTypeShoot {
shot := s.validateShot(player, input)
if shot != nil {
s.applyDamage(shot)
}
}
// 4. Visibility culling: non invia posizioni di nemici non visibili
// Previene wall hack via packet sniffing
visiblePlayers := s.lineOfSight.GetVisiblePlayers(player)
return &GameStateUpdate{
Position: player.Position,
VisiblePlayers: visiblePlayers, // Solo chi il player PUO vedere
// Non include mai posizioni di giocatori non visibili!
}
}
// validateShot: hit detection server-side con lag compensation
func (s *AuthoritativeServer) validateShot(shooter *PlayerState, input PlayerInput) *ShotResult {
// Lag compensation: ricostruisci lo stato del mondo al momento dello sparo lato client
// Il client ha inviato l'input con timestamp: usa quello per trovare lo stato server passato
pastState := s.history.GetStateAt(input.ClientTimestamp - shooter.Latency)
// Verifica line-of-sight al momento dello sparo
if !s.lineOfSight.HasLoS(shooter.Position, input.TargetPosition, pastState) {
return nil // Muro tra shooter e target: no shot
}
// Verifica distanza massima dell'arma
weapon := shooter.GetEquippedWeapon()
dist := shooter.Position.DistanceTo(input.TargetPosition)
if dist > weapon.MaxRange {
return nil // Fuori portata
}
// Verifica che il target esista e sia effettivamente alla posizione indicata
// Con tolerance per il lag (lagCompensation)
target := pastState.GetPlayerAt(input.TargetPosition, lagCompensationRadius(shooter.Latency))
if target == nil {
return nil // Nessun target in quella posizione
}
return &ShotResult{
ShooterID: shooter.ID,
TargetID: target.ID,
Damage: weapon.CalculateDamage(dist),
Headshot: input.IsHeadshot && s.validateHeadshot(shooter, target, pastState),
}
}
3. Aim Bot Detection: Analiză statistică
Un bot de țintire produce modele de țintire care sunt imposibile statistic pentru un om: unghiuri de rotație fotografii instantanee, cu o precizie de 100%, urmărire perfectă. Detectarea se bazează pe analiză statistici ale mișcărilor mouse-ului/stick-ului de-a lungul timpului, comparând jucătorul cu distribuția a populatiei.
// aim_analysis.go - Statistical aim bot detection
package anticheat
import (
"math"
"time"
)
// AimSample: campione di movimento del mouse/stick in un singolo frame
type AimSample struct {
DeltaYaw float64 // Angolo orizzontale (gradi/frame)
DeltaPitch float64 // Angolo verticale
OnTarget bool // Se punta verso un nemico
SnapToTarget float64 // Distanza di snap verso il target più vicino
Timestamp time.Time
}
// PlayerAimProfile: profilo cumulativo dei movimenti di mira
type PlayerAimProfile struct {
PlayerID string
Samples []AimSample
SnapRates []float64 // Storico snap-to-target rates
FlickAngles []float64 // Angoli dei flick shots
}
// AnalyzeAim: restituisce un aim suspicion score (0.0 - 1.0)
func AnalyzeAim(profile *PlayerAimProfile) AimAnalysisResult {
if len(profile.Samples) < 100 {
return AimAnalysisResult{Score: 0, Insufficient: true}
}
// Feature 1: Snap rate analysis
// Un aimbot "snappa" al target con velocità sovrumana
snapsToTarget := 0
for _, s := range profile.Samples {
if s.OnTarget && s.SnapToTarget > 50 { // 50 gradi snap in un frame = impossibile
snapsToTarget++
}
}
snapRate := float64(snapsToTarget) / float64(len(profile.Samples))
// Feature 2: Micro-correction analysis
// Gli aimbot mostrano pattern di micro-correzione innaturali dopo ogni sparo
corrections := extractMicroCorrections(profile.Samples)
correctionMean := mean(corrections)
correctionStd := stddev(corrections, correctionMean)
// Feature 3: Jitter analysis
// Il mouse umano ha jitter naturale. Zero jitter = aimbot
jitter := calculateJitter(profile.Samples)
humanJitterRange := [2]float64{0.3, 3.0} // Range tipico umano (gradi/frame)
// Feature 4: FOV tracking efficiency
// Aimbot = efficienza quasi perfetta nel FOV del target
trackingEfficiency := calculateTrackingEfficiency(profile.Samples)
// Calcola score combinato (threshold empirici da dati reali)
score := 0.0
if snapRate > 0.05 { // > 5% snap shots = sospetto
score += 0.4 * math.Min(snapRate/0.05, 1.0)
}
if jitter < humanJitterRange[0] { // Jitter troppo basso = aimbot
score += 0.3 * (1.0 - jitter/humanJitterRange[0])
}
if trackingEfficiency > 0.92 { // > 92% tracking efficiency = sovrumano
score += 0.3 * math.Min((trackingEfficiency-0.92)/0.08, 1.0)
}
return AimAnalysisResult{
Score: score,
SnapRate: snapRate,
CorrectionStd: correctionStd,
Jitter: jitter,
TrackingEfficiency: trackingEfficiency,
Suspicious: score > 0.7,
}
}
func mean(data []float64) float64 {
sum := 0.0
for _, v := range data { sum += v }
return sum / float64(len(data))
}
func stddev(data []float64, m float64) float64 {
variance := 0.0
for _, v := range data { variance += (v - m) * (v - m) }
return math.Sqrt(variance / float64(len(data)))
}
4. Machine Learning: Transformers for Behavioral Detection
Analiza statistică surprinde trucuri mai grosolane, dar trucuri avansate (de exemplu, roboții țintiți cu jitter artificiale) necesită abordări ML. Cele mai recente cercetări (AntiCheatPT, 2025) arată cum i Transformers aplicate la secvențele de acțiuni de joc ating o precizie de 96,94% și AUC de 98,36% în detecție, depășind LSTM și CNN tradițional.
// Feature engineering per ML anti-cheat
// Estrae feature da una finestra temporale di azioni di gioco
from typing import List, Dict
import numpy as np
from dataclasses import dataclass
@dataclass
class GameAction:
timestamp: float
action_type: str # "move", "shoot", "reload", "ability"
delta_x: float # Movimento mouse X
delta_y: float # Movimento mouse Y
aim_x: float # Angolo mira
aim_y: float
on_target: bool # True se mira verso un nemico
result: str # "hit", "miss", "kill"
def extract_features(actions: List[GameAction], window_size: int = 100) -> np.ndarray:
"""
Estrae feature dalla finestra di azioni per classificazione ML.
Output: array di shape (window_size, feature_dim) per Transformer
"""
features = []
for i in range(min(len(actions), window_size)):
a = actions[i]
# Feature cinematiche (movimento)
aim_speed = np.sqrt(a.delta_x**2 + a.delta_y**2)
aim_accel = 0.0
if i > 0:
prev_speed = np.sqrt(actions[i-1].delta_x**2 + actions[i-1].delta_y**2)
dt = a.timestamp - actions[i-1].timestamp
aim_accel = (aim_speed - prev_speed) / max(dt, 0.001)
# Feature di target acquisition
snap_magnitude = 0.0
if a.on_target and i > 0 and not actions[i-1].on_target:
snap_magnitude = aim_speed # Velocita di snap al target
# Feature di shooting behavior
is_shoot = 1.0 if a.action_type == "shoot" else 0.0
is_hit = 1.0 if a.result == "hit" else 0.0
is_kill = 1.0 if a.result == "kill" else 0.0
# Feature inter-azione
time_since_last_shoot = 0.0
for j in range(i-1, max(0, i-10), -1):
if actions[j].action_type == "shoot":
time_since_last_shoot = a.timestamp - actions[j].timestamp
break
feature_vector = np.array([
aim_speed, # Velocita di mira
aim_accel, # Accelerazione mira
a.delta_x, # Movimento X raw
a.delta_y, # Movimento Y raw
snap_magnitude, # Magnitudine snap
float(a.on_target), # On target flag
is_shoot, # E uno sparo?
is_hit, # Ha colpito?
is_kill, # Ha ucciso?
time_since_last_shoot, # Tempo dall'ultimo sparo
])
features.append(feature_vector)
# Padding se la finestra e più corta di window_size
while len(features) < window_size:
features.append(np.zeros(10))
return np.array(features, dtype=np.float32)
# Modello Transformer per classificazione comportamentale (PyTorch)
import torch
import torch.nn as nn
class AntiCheatTransformer(nn.Module):
def __init__(self, feature_dim=10, d_model=64, nhead=4, num_layers=3, window_size=100):
super().__init__()
self.input_projection = nn.Linear(feature_dim, d_model)
self.positional_encoding = nn.Embedding(window_size, d_model)
encoder_layer = nn.TransformerEncoderLayer(
d_model=d_model, nhead=nhead, dim_feedforward=256,
dropout=0.1, batch_first=True
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
self.classifier = nn.Sequential(
nn.Linear(d_model, 32),
nn.ReLU(),
nn.Dropout(0.1),
nn.Linear(32, 2) # 2 classi: legittimo, cheater
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# x: (batch, window_size, feature_dim)
batch_size, seq_len, _ = x.shape
positions = torch.arange(seq_len, device=x.device).unsqueeze(0).expand(batch_size, -1)
x = self.input_projection(x) + self.positional_encoding(positions)
x = self.transformer(x)
# Usa il CLS token (prima posizione) per classificazione
x = self.classifier(x[:, 0, :])
return x # logits: (batch, 2)
5. Managementul fals pozitiv: protejarea jucătorilor nevinovați
Cea mai gravă greșeală a unui sistem anti-cheat și a interzicerii jucătorilor nevinovați: un VPN care simulează latență mare, un jucător de înaltă calificare cu reacții excepționale, un controler care funcționează defectuos care generează intrări anormale. Un fals pozitiv distruge încrederea jucătorului și este aproape imposibil recuperați-l. Sistemul trebuie să fie proiectat cu mai multe straturi de confirmare înainte de fiecare interdicție.
// sanction_pipeline.go - Multi-layer sanction decision pipeline
package anticheat
type SuspicionReport struct {
PlayerID string
ReportType string // "speed_hack", "aim_bot", etc.
Score float64 // 0.0 - 1.0
Evidence []Evidence
Timestamp time.Time
}
type SanctionPipeline struct {
suspicionDB *SuspicionDatabase
accountAge *AccountAgeService
humanReview *HumanReviewQueue
}
// ProcessSuspicion: decide cosa fare con una segnalazione sospetta
func (p *SanctionPipeline) ProcessSuspicion(report SuspicionReport) SanctionDecision {
// Layer 1: Accumulo prove nel tempo
// Una singola violazione non e sufficiente per agire
history := p.suspicionDB.GetHistory(report.PlayerID, 30*24*time.Hour) // 30 giorni
history = append(history, report)
// Calcola score cumulativo pesato per recency
cumulativeScore := 0.0
for i, h := range history {
age := time.Since(h.Timestamp).Hours() / 24 // giorni
weight := math.Exp(-age / 7) // Decadimento esponenziale su 7 giorni
cumulativeScore += h.Score * weight * (float64(i+1) / float64(len(history)))
}
// Layer 2: Account age factor
// Account nuovi con alto suspicion score = più probabile cheater
accountAgeDays := p.accountAge.GetAgeDays(report.PlayerID)
if accountAgeDays < 7 {
cumulativeScore *= 1.3 // Boost per account nuovi
} else if accountAgeDays > 365 {
cumulativeScore *= 0.8 // Discount per account vecchi e stabiliti
}
// Layer 3: Decision tree
switch {
case cumulativeScore >= 0.95:
// Auto-ban: evidenze schiaccianti, molto difficile falso positivo
return SanctionDecision{
Action: "permanent_ban",
AutoApply: true,
Reason: fmt.Sprintf("cumulative_score=%.3f", cumulativeScore),
}
case cumulativeScore >= 0.80:
// Soft ban temporaneo + review umana obbligatoria
return SanctionDecision{
Action: "temp_ban_24h",
AutoApply: true,
SendToReview: true,
Reason: "high_suspicion_pending_review",
}
case cumulativeScore >= 0.60:
// Solo monitoraggio aumentato, nessuna sanzione automatica
p.suspicionDB.SetMonitoringLevel(report.PlayerID, MonitoringHigh)
return SanctionDecision{
Action: "monitor_only",
AutoApply: false,
}
default:
// Falso positivo probabile: solo log
return SanctionDecision{Action: "log_only", AutoApply: false}
}
}
6. Analiza reluării: Detectare post-hoc
Nu toate trucurile sunt detectabile în timp real. Analiza reluării - posibilă datorită telemetria completă înregistrată de server - vă permite să revizuiți potrivirile după a player a fost raportat de alții, aplicând analize mai grele din punct de vedere computațional.
-- ClickHouse: Query per identificare candidati sospetti da analisi replay
-- Identifica giocatori con statistiche outlier negli ultimi 7 giorni
SELECT
player_id,
count() AS total_matches,
avg(toFloat64OrZero(payload['headshot_rate'])) AS avg_headshot_rate,
avg(toFloat64OrZero(payload['kda'])) AS avg_kda,
avg(toFloat64OrZero(payload['avg_ttk_ms'])) AS avg_ttk_ms,
-- Accuracy Z-Score rispetto alla media della regione
-- Z > 3: più di 3 sigma sopra la media = outlier statistico
(avg(toFloat64OrZero(payload['headshot_rate'])) -
avg(avg(toFloat64OrZero(payload['headshot_rate'])))
OVER (PARTITION BY toStartOfDay(server_ts))) /
stddevPop(toFloat64OrZero(payload['headshot_rate']))
OVER (PARTITION BY toStartOfDay(server_ts)) AS headshot_zscore,
-- Ratio di report ricevuti da altri player
countIf(payload['was_reported'] = 'true') / count() AS report_rate
FROM game_analytics.events_all
WHERE event_type = 'gameplay.match_end'
AND server_ts >= now() - INTERVAL 7 DAY
GROUP BY player_id
HAVING
total_matches >= 10 -- Minimo partite per avere dati significativi
AND (
headshot_zscore > 3 -- Statistically impossible accuracy
OR avg_ttk_ms < 100 -- Kills troppo veloci
OR report_rate > 0.3 -- > 30% partite con segnalazioni
)
ORDER BY headshot_zscore DESC, report_rate DESC
LIMIT 100;
Greșeli frecvente în Anti-Cheat
- Ban numai pentru K/D mare: Un jucător foarte bun are K/D mare. Analizează întotdeauna în combinație cu semnale multiple (modele de țintire, viteza, rapoarte) înainte de a acționa.
- Ignorați latența în comenzi: Cu compensare lag, un jucător cu 100 ms de latență se poate simți ca „a trage prin pereți”. Calibrați toleranțele de validare pe baza latenței reale a jucătorului.
- Sistem clar anti-cheat: Nu expuneți niciodată detaliile sistemului anti-cheat: trișorii analizează răspunsurile pentru a înțelege ce să declanșeze și ce să evite. Utilizați răspunsuri ambigue și întârzieri aleatorii înainte de interdicții.
- Nici un proces de apel: Chiar și cel mai precis sistem face greșeli. Oferă a un proces de apel clar și uman pentru interdicțiile contestate.
Concluzii
Un sistem eficient anti-cheat în 2025 necesită o abordare pe mai multe straturi:arhitectura server-autoritar ca un fundament de neatins, cel validare statistică pentru modele anormale și învățarea automată (în special Transformers) pentru detectarea comportamentală sofisticată. Nici unul dintre cei trei singur nu este suficient.
Gestionarea fals-pozitivelor este la fel de importantă ca și detectarea: un sistem care interzice multe inocent și mai rău decât nici un sistem anti-cheat. Conducta de sancțiuni multistrat cu revizuire drepturile omului obligatorii pentru cazurile limită și procesul de apel deschis nu sunt negociabile.
Următorii pași în seria Game Backend
- Articolul precedent: Sistem de potrivire: ELO, Glicko-2 și Queue Management
- Articolul următor: Open Match și Nakama: Open-Source Game Backend
- Serii înrudite: Web Security - API Security and Vulnerability Assessment







