Sécurité & confidentialité

Protection contre les abus

Limites de débit et détection là où ça compte le plus.

Les endpoints sensibles sont limités en débit côté CDN et applicatif, chaque échec d'authentification est envoyé à notre monitoring, et l'allow-list CORS est explicite — aucune page tierce ne peut agir sur votre compte sans votre consentement. Un attaquant qui tente de deviner un mot de passe, de faire du credential stuffing ou de brute-forcer un code d'appairage se heurte à un blocage temporaire en quelques secondes.

Limitation de débit

Les endpoints sensibles (connexion, inscription, confirmation, appairage d'appareil, OAuth) sont protégés par un limiteur de débit côté applicatif et côté CDN. Un attaquant qui tenterait de deviner un mot de passe ou un code d'appairage se heurte rapidement à un blocage temporaire.

Détection d'échecs d'authentification

Chaque tentative qui échoue est étiquetée (type, raison) et envoyée à notre système de monitoring, ce qui nous permet de détecter un pic d'attaques en temps réel.

CSRF et CORS

Les endpoints web sont protégés contre les requêtes inter-sites falsifiées. Les origines autorisées à appeler notre API sont explicitement listées — aucune page web tierce ne peut faire agir votre compte sans votre consentement.

Throttles conscients de l'IP réelle

Le throttle d'inscription guest lit à la fois request.ip et CF-Connecting-IP, donc un attaquant ne peut pas vaincre la limite en cyclant des proxies ouverts derrière notre CDN.

Lockout par email

La connexion est limitée par IP et par email. Le credential stuffing d'un seul compte à travers de nombreuses IPs atteint quand même le budget par email et se fait bloquer, même si l'attaquant dispose d'un grand botnet.

Mitigation DDoS à deux couches

Cloudflare absorbe les attaques volumétriques en amont de notre origine ; la limitation applicative s'occupe des abus low-and-slow qui survivent au CDN. Aucune couche à elle seule ne suffit ; ensemble elles couvrent les deux vecteurs.

Webhooks signés

Chaque webhook entrant que nous acceptons (PhoneVoice, Stripe, Postmark) porte une signature HMAC que nous vérifions contre un secret partagé. Les payloads webhook forgés sont rejetés avant d'atteindre la moindre logique applicative.

Pas de default-allow

Chaque nouveau endpoint doit explicitement opt-in pour être accessible sans authentification. Le défaut est : session valide requise. Personne ne peut exposer accidentellement une action sensible en oubliant un check d'auth.

Plongée technique

Budgets de throttle par endpoint

Chaque endpoint sensible a son propre budget de limitation, calibré sur ce dont un utilisateur légitime a besoin et pas plus :

  • 10 connexions par 15 min, par IP ET par email
  • 5 inscriptions par heure par IP ; 3 inscriptions guest par heure par IP + par IP réelle
  • 20 tentatives de code de confirmation par 15 min par IP
  • 30 appels OAuth par 15 min par IP
  • 10 tentatives d'appairage d'appareil par 15 min par IP
  • 300 requêtes totales par 5 min par IP, tout endpoint confondu sauf assets et le WebSocket ActionCable

Au-dessus du budget nous retournons HTTP 429 avec un en-tête Retry-After et loggons une notification throttle.rack_attack pour que les attaquants soient visibles sur nos dashboards. Le cache store est Redis en production, donc le budget est partagé entre tous les web workers.

Allow-list CORS

Les seules origines autorisées à appeler notre API sont les sous-domaines twoody.com, les schémas mobile/montre (capacitor://localhost, ionic://localhost, twoody://), et localhost/LAN en dev. Tout le reste reçoit un rejet de preflight CORS avant que la requête ne touche la moindre logique applicative.

Les credentials sont désactivés sur CORS — une origine tierce ne peut pas obtenir un cookie de session depuis notre API même si elle essayait. C'est le remplacement moderne du CORS « grand ouvert » que l'app portait historiquement.

Retour de signal d'abus

Chaque échec d'authentification (mauvais mot de passe, email inconnu, code de confirmation expiré, JWT rejoué, throttle atteint) est étiqueté avec un type et une raison d'échec, et envoyé à notre monitoring. Un pic soudain sur une classe d'échec spécifique (par ex. unknown_email depuis un seul AS) est visible sur un dashboard en quelques secondes et peut être escaladé en blocage CDN sans redéployer.

Le même canal alimente la boîte security@ : un motif inhabituel qui n'est pas encore un throttle peut être revu manuellement avant qu'il ne passe à l'échelle.

Quelques secondes de 429 sont le coût attendu d'être connecté à l'internet ouvert. Nous calibrons les budgets pour que l'usage légitime soit invisible et l'abus coûteux — jamais l'inverse.

Sujets liés