guard/docs/research/anti-bot.md
loki5512344 269daa071f
v0.3: 6-layer architecture complete
Layers:
  Layer 1: XDP/eBPF — TCP state machine, SYN throttle, blacklist, ringbuf
  Layer 2: PoW Challenge — SHA-256 hashcash, dynamic difficulty, constant-time verify
  Layer 3: Rust Core — HMAC handshake, rate limit, death code (existing)
  Layer 4: Velocity — Physics check, CAPTCHA, protocol verification
  Layer 5: Paper — Heartbeat, auto-registration (existing)
  Layer 6: Traffic Intel — EWMA, 168h profiling, reputation, alerts

Infra: XDP→Prometheus metrics, ClickHouse + Grafana dashboard, Docker Compose
Testing: 100-IP DDoS simulation, MHDDoS ref analysis, load test report
Fixes: VarInt sign extension UB, pure ACK deadlock, RST/FIN cleanup
Ref: MHDDoS, Sonar, LimboFilter, AtomGuard, Infrarust, MC-XDP-eBPF, PowGo
2026-07-21 15:47:36 +02:00

17 KiB
Raw Permalink Blame History

Anti-Bot стратегия

Актуально: v0.2+


6 слоёв антибот защиты

┌──────────────────────────────────────────────────────────────────┐
│  Слой 1: XDP/eBPF                    дроп L3/L4 на уровне ядра │
│  ─────────────────────────────────────                              │
│  TCP state machine: SYN → SYN-ACK → ожидание MC handshake         │
│  SYN throttle: N SYNs/IP/сек → временный бан                      │
│  Invalid flags: SYN+FIN, SYN+RST, URG → дроп                     │
│  UDP: дроп (MC работает только по TCP)                           │
│                                                                   │
│  Бот не может: открыть >N TCP соединений/сек с одного IP         │
├──────────────────────────────────────────────────────────────────┤
│  Слой 2: PoW Challenge                  анти-handshake-flood     │
│  ─────────────────────────────────────                              │
│  Перед HMAC handshake клиент решает SHA256 hashcash:              │
│  1. Edge шлёт {challenge, difficulty, allowedHex, timestamp}      │
│  2. Клиент ищет nonce: SHA256(challenge + nonce) начинается с    │
│     difficulty символов из allowedHex                              │
│  3. Edge верифицирует, challenge одноразовый (timestamp + nonce)  │
│  4. Dynamic difficulty: 12 при атаке, 4 в спокойное время        │
│                                                                   │
│  Бот не может: открывать >50 handshake/сек (PoW жрёт CPU)        │
│  Nonce replay невозможен: challenge + timestamp уникальны         │
├──────────────────────────────────────────────────────────────────┤
│  Слой 3: Rust Core                       L7 проверки             │
│  ─────────────────────────────────────                              │
│  Rate limit: N conn/IP/сек (token bucket)                         │
│  Death code: 8 паттернов малициозных пакетов → автобан           │
│  Blacklist: global + per-IP, Redis sync                          │
│  ASN reputation: датацентры → строже, residential → мягче         │
│  Timeout: 5 сек на полный handshake (anti-Slow Loris)            │
│                                                                   │
│  Бот не может: слать >5 conn/сек, слать мусор в пакетах          │
├──────────────────────────────────────────────────────────────────┤
│  Слой 4: Velocity                        верификация игроков     │
│  ─────────────────────────────────────                              │
│  Domain whitelist: блок прямых IP, разрешены только наши домены  │
│  HMAC verify: hostname содержит \0shield\0<sig>                  │
│  Falling check: spawn Y=512, 128 тиков физики падения            │
│  Protocol check: Transaction, SetHeldItem, ArmAnimation          │
│  Vehicle check: Boat + Minecart gravity + paddle packets          │
│  CAPTCHA: map item или PoW                                        │
│                                                                   │
│  Бот не может: зайти без HMAC, пройти физику без симуляции MC   │
├──────────────────────────────────────────────────────────────────┤
│  Слой 5: Traffic Intelligence              аналитика            │
│  ─────────────────────────────────────                              │
│  168-hour профиль: baseline соединений по часам и дням недели    │
│  EWMA adaptive thresholds: аномалии относительно baseline        │
│  Z-Score: 3σ от среднего → алерт                                 │
│  Reputation: score -100..+100, влияет на rate limit множитель    │
│  Attack detection: CPS > threshold → режим атаки                 │
│                                                                   │
│  Бот не может: атаковать незаметно — дёргает threshold           │
├──────────────────────────────────────────────────────────────────┤
│  Слой 6: Verified DB (Redis)              кэш верификации        │
│  ─────────────────────────────────────                              │
│  HMAC-SHA256 fingerprint: SHA256(secret, username, IP)            │
│  TTL: 24 часа без активности, продлевается при каждом входе     │
│  Skip: верифицированные проходят слои 2-4 мгновенно             │
│                                                                   │
│  Бот не может: подделать fingerprint (HMAC, не hashCode)         │
└──────────────────────────────────────────────────────────────────┘

Путь игрока через защиту

Новый игрок
    |
    v
┌──────────────────┐
│  XDP/eBPF        │  TCP handshake processing
│  Ядро Linux      │  Прошёл SYN throttle + state machine
└────────┬─────────┘
         v (TCP соединение установлено)
┌──────────────────┐
│  PoW Challenge   │  SHA256 hashcash
│  Rust            │  Dynamic difficulty, одноразовый challenge
└────────┬─────────┘
         v (PoW решён)
┌──────────────────┐
│  Rust Core       │  Rate limit, Death code, Blacklist
│  userspace       │  HMAC sign hostname
└────────┬─────────┘
         v (валидный MC handshake + HMAC)
┌──────────────────┐
│  Velocity        │  Domain whitelist, HMAC verify
│  Java            │  Falling check → Protocol check
│                  │  → Vehicle check → CAPTCHA
└────────┬─────────┘
         v (верифицирован)
┌──────────────────┐
│  Hub / Game      │  Игрок на сервере
│  Server          │
└──────────────────┘

Защита от AI-ботов (2026)

Проблема

Современные attack frameworks обходят существующие anti-bot решения:

Решение Обход
Sonar gravity check AI симулирует MC физику
LimboFilter falling Робот считает parabola
Map CAPTCHA (Sonar) OCR решает 3-4 символа
Математические задачи AI решает за <100ms
Timing check AI имитирует human timing

Что работает против AI

✓ PoW (Layer 2):        вычислительная стоимость, GPU не помогает
                        достаточно (SHA256 не memory-hard)
✓ HMAC (Layer 3+4):     криптография, не обходится без ключа
✓ ASN reputation:       датацентры = боты
✓ Dynamic difficulty:   при атаке повышаем PoW сложность
✓ Многослойность:       нужно обойти 6 слоёв, а не 1

Fingerprinting (исправленный)

// В отличие от Sonar (использующего hashCode + сдвиги без соли),
// Rampart использует HMAC-SHA256 с ротацией ключа:

use hmac::{Hmac, Mac};
use sha2::Sha256;

type HmacSha256 = Hmac<Sha256>;

pub fn compute_fingerprint(secret: &[u8], username: &str, ip: &str) -> String {
    let mut mac = HmacSha256::new_from_slice(secret)
        .expect("HMAC key");
    mac.update(username.as_bytes());
    mac.update(b"\0");
    mac.update(ip.as_bytes());
    let result = mac.finalize();
    hex::encode(result.into_bytes())
}

// Свойства:
// - Нет коллизий (SHA256)
// - Нет подделки (HMAC, не hash code)
// - Нет обратной инженерии (secret на edge ноде)
// - Ротация ключа каждые 24ч
// - Разные secret для разных слоёв (XDP_key, PoW_key, HMAC_key)

Verified Player Cache

// После прохождения всех слоёв — fingerprint в Redis:
//
// Ключ:    rampart:verified:{sha256_fingerprint}
// Значение: { ip, username, verified_at, last_seen, ttl }
// TTL:     24h (продлевается при каждом входе)
//
// При повторном входе:
// 1. Вычисляем fingerprint
// 2. Проверяем Redis
// 3. Если есть и IP совпадает → слои 2-4 пропускаются
// 4. Если IP изменился → проходим верификацию заново

pub fn is_verified(redis: &Client, username: &str, ip: &str) -> bool {
    let fp = compute_fingerprint(&get_secret(), username, ip);
    let key = format!("rampart:verified:{}", fp);

    match redis.get::<String>(&key) {
        Ok(Some(data)) => {
            let entry: VerifiedEntry = serde_json::from_str(&data).ok()?;
            if entry.ip == ip {
                // Продлеваем TTL
                let _ = redis.expire(&key, 86400);
                return true;
            }
        }
        _ => {}
    }
    false
}

PoW Challenge (Layer 2)

// Hashcash-style proof of work
// Адаптировано из PowGo: +timestamp, +per-request challenge, dynamic difficulty

pub struct Challenge {
    pub token: [u8; 16],        // случайный per-request
    pub timestamp: u64,          // unix ms
    pub difficulty: u8,          // 4-12, динамический
    pub allowed_hex: &'static str, // "012def" по умолчанию
}

pub struct Solution {
    pub token: [u8; 16],
    pub nonce: u64,
}

pub fn verify(challenge: &Challenge, solution: &Solution) -> bool {
    // 1. Timestamp validity (max 30 seconds old)
    let age = current_timestamp_ms() - challenge.timestamp;
    if age > 30_000 { return false; }

    // 2. Token match
    if challenge.token != solution.token { return false; }

    // 3. Hash verification
    let mut data = [0u8; 32];
    data[..16].copy_from_slice(&challenge.token);
    data[16..24].copy_from_slice(&solution.nonce.to_le_bytes());

    let hash = sha256(&data);
    let hex = hex::encode(hash);
    for i in 0..challenge.difficulty as usize {
        let c = hex.as_bytes()[i] as char;
        if !challenge.allowed_hex.contains(c) {
            return false;
        }
    }
    true
}

// Dynamic difficulty adjustment
pub fn get_difficulty(cps: u64, attack_mode: bool) -> u8 {
    match (cps, attack_mode) {
        (_, true) | (cps, _) if cps > 500 => 12,
        (cps, _) if cps > 100 => 10,
        (cps, _) if cps > 50  => 8,
        _ => 4,
    }
}

Матрица атак MHDDoS vs Rampart

Анализ MHDDoS — самый популярный DDoS тул на Python (25k+ stars).

Метод атаки Тип Как работает Блокируется слоем Примечание
SYN L4 RAW SYN flood с подделкой source IP Layer 1 (XDP SYN throttle) Если XDP отключён — iptables SYN cookie
TCP L4 randbytes(1024) в TCP сокет Layer 1 (conntrack) Аномальный трафик, мало данных
UDP L4 randbytes(1024) через UDP Layer 1 (UDP drop) MC только TCP, UDP дропается
CPS L4 Открыть/закрыть TCP Layer 1 (SYN throttle) + Layer 3 (rate limit) 50+ conn/s → block
CONNECTION L4 Держать TCP открытым Layer 1 (idle timeout) + Layer 3 (conntrack) 30s idle → evict
MINECRAFT L4 Handshake + ping флуд Layer 2 (PoW) + Layer 3 (rate limit) PoW требует CPU
MCBOT L4/L7 Полная эмуляция игрока (login → чат) Layer 4 (Physics) + Layer 6 (reputation) Самый опасный для MC
ICMP L4 RAW ICMP echo flood Layer 1 (ICMP rate-limit) На уровне ядра
DNS/NTP/MEM L4 AMP Amplification через рефлекторы Layer 1 (UDP drop) UDP не на MC порты
GET/POST/HEAD L7 HTTP флуд Layer 3 (rate limit) 100 req/s → block
CFB L7 HTTP через cloudscraper (обходит CF) Layer 3 (rate limit per IP) Прокси не спасают — Rampart видит реальный IP
SLOW L7 Slowloris: медленные заголовки Layer 3 (read timeout 10s) Таймаут закрывает
BOT L7 Имитация Googlebot Layer 6 (168h профиль) Аномалия в час-слоте
BOMB L7 HTTP/2 через SOCKS5 прокси Layer 6 (EWMA thresholds) PPS аномалия
DGB L7 Обход DDoS-Guard Layer 3 (HMAC verify) После HMAC — невалидная подпись
APACHE L7 Range-атака (CVE-2011-3192) Layer 3 (packet inspect) Малый HTTP трафик

Сводка

  • Layer 1 (XDP) блокирует: SYN, UDP, ICMP, AMP, TCP flood
  • Layer 2 (PoW) блокирует: MINECRAFT handshake flood
  • Layer 3 (Core) блокирует: CPS, CONNECTION, HTTP flood, SLOW, APACHE
  • Layer 4 (Physics) блокирует: MCBOT (неестественное движение)
  • Layer 6 (Traffic Intel) блокирует: BOT, BOMB, аномалии по 168h профилю
  • Не покрыто полностью: CFB через 10k+ уникальных IP (нужна репутация Layer 6)

Известные проблемы в других решениях

Проблема Где найдено Наше решение
Fingerprint = hashCode + сдвиги, без соли Sonar HMAC-SHA256 с ротацией ключа
CAPTCHA проходима AI (3-4 символа, map colors) Sonar #531 PoW вместо/поверх CAPTCHA
4x re-verification race Sonar #611 Idempotent finish, atomic state
KeepAlive ID plaintext Sonar Challenge-response с HMAC
QuietDecoderException как control flow Sonar Result<T, E> без исключений
checkY() fast-forward LimboFilter Строгий шаг: 1 tick за вызов
ignoredTicks не сбрасывается LimboFilter Сброс на валидном move
Memory leak MapData LimboFilter #118 Weak refs, explicit cleanup
Isolation Forest мёртвый код AtomGuard Реально используем или убираем
EWMA variance double-smoothing AtomGuard Правильная формула
Race в pipeline checks.clear/addAll AtomGuard Copy-on-write
SynFloodDetector при <15 IP отключается AtomGuard Per-IP fallback
AntiBot plugin пустой Infrarust Реализован с первого коммита
Rate limit disabled by default Infrarust Enabled по умолчанию
TCP handshake deadlock (pure ACK drop) MC-XDP-eBPF Не дропать pure ACK
Stale state on RST/FIN MC-XDP-eBPF Удалять entry на RST
Nonce replay PowGo Per-request challenge + timestamp
Static difficulty PowGo Dynamic по CPS