Synthèse des décisions et garde-fous. Source d'autorité opérationnelle : CLAUDE.md §4.
| Acteur | Capacité | Mitigation |
|---|---|---|
| Joueur honnête | Joue normalement | N/A |
| Joueur tricheur (devtools) | Lire le JS, intercepter les réponses | Solutions JAMAIS envoyées avant fin partie. |
| Scraper | Frapper l'API à la chaîne | Rate limit, IDs opaques UUID, hCaptcha si pic. |
| Bot d'inscription | Spam comptes pour fausser leaderboard | Keycloak + Altcha-style PoW + email verification. |
| Attaquant CI | Compromettre une dépendance, pousser une image | Trivy CRITICAL bloque CI, Renovate auto, Snyk pré-release. |
| Attaquant infra | Pivot depuis le VPS | OpenBao secrets, ci-kalidoku scope ultra-restreint, Wazuh HIDS. |
- Keycloak = source de vérité (
auth.calixteair.fr, realmkalidoku). - IdP fédérés : Google + Discord + email/password local.
- Email verification obligatoire sauf Google (déjà vérifié par Google).
kalidoku.users(id, kc_sub, pseudo, created_at, role)— mini table locale, lie ausubKeycloak.
- Cookie
__Host-sessionSecure HttpOnly SameSite=Lax — Lax (et non Strict) car le callback OIDC est un redirect cross-site depuis Keycloak ; Strict empêcherait l'envoi du cookie au premier rebond. CSRF reste couvert par__Host-+ Secure + HttpOnly + play-token HMAC lié au device. - Token = 32 bytes random, hash SHA-256 en DB.
- TTL 30 jours, glissant : si session > 7 jours, on émet un nouveau token au prochain hit.
- Logout =
DELETE FROM sessions WHERE token_hash = ?.
core/validator.rsest la seule porte de validation des réponses.- À chaque
POST /play:- Auth via cookie session.
- Vérifier
play_tokenHMAC (signature{game_id, device_id, started_at}). - Vérifier que la partie n'est pas finie.
core::validator::validate_answer→{Match, Wrong, UnknownEntity, AlreadyUsed}.- Mettre à jour
games.answers,games.score,games.mistakes.
- Solutions complètes (
solutionsByCell) renvoyées seulement par/resultet/abandon.
- Altcha PoW invisible sur inscription Keycloak via SPI custom (cf. wiki
[[devsecvault-altcha-spi]]). - Altcha PoW côté backend Rust également : challenge HMAC-SHA256 émis par le serveur, résolu en ~50–500 ms côté client (invisible), vérifié au prochain endpoint sensible (start game, duel create).
- Self-hosted, RGPD friendly : zéro service tiers, aucune télémétrie navigateur.
- Rate limit
tower_governor:- 1 req / 250 ms par device (cookie).
- 60 req / min par IP toutes routes confondues.
- Burst 10, token bucket.
- IDs UUID v7 partout, jamais d'auto-increment exposé.
- Pagination par cursor opaque (HMAC-signé) sur tous les endpoints liste.
- Liens de duel signés HMAC dans
?sig=(déjà dans OpenAPI/api/duels/{id}).
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'nonce-<random>'; connect-src 'self' https://hcaptcha.com; frame-src https://hcaptcha.com
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
- Tout via OpenBao (cf.
infra/bao/setup.md). - Charset DB password : alphanumeric uniquement (gotcha YAML/sed/
$shell expansion — voir wiki Wazuh). - HMAC keys : 32+ bytes random base64.
- Jamais dans logs : tronquer/hasher PII.
- gitleaks sur chaque PR + pre-commit local.
- Trivy scan FS sur PR + scan image après push, CRITICAL = échec.
- Snyk lancé manuellement avant chaque release
v*. - Renovate auto-merge minor/patch en green CI.
- Image runtime distroless nonroot, surface d'attaque minimale.
- Pages légales
/legal/{privacy,cookies,terms}— copie modèle DSV. - Suppression de compte : flag
users.deleted_at+ scrub PII (pseudo→deleted_<n>,email→ null), score conservé pour ne pas casser les leaderboards historiques. - Export JSON sur demande via
/api/me/export. - Logs de production rétention 30j puis anonymisation IP.
- Bandeau cookie minimal (Umami est privacy-first, hCaptcha = stricte nécessité).
- Logs JSON
tracing→ stdout → Wazuh agent host. - Alertes Wazuh (rules level ≥ 10) → mail
soc@calixteair.fr(sidecar postfix → Mailcow). - Métriques Prometheus optionnelles : exposer
/metricsOAuth-protégé pourprometheus-socexistant. - Uptime externe : healthchecks.io ping
/api/healthtoutes les 5 min → notif Discord en cas de DOWN.
- Compromission ci-kalidoku →
userdel -r ci-kalidoku+ remplacer GitHub Secret. - Fuite de HMAC key → rotate secret Bao + restart server (sessions invalidées).
- Cheat massif → réinitialiser leaderboard du jour, relancer la grille.
- DDoS → Cloudflare bloqué pour toi → activer challenge JS sur NPM via CrowdSec bouncer (déjà en place).