Prévenir l'Account Takeover (ATO) avec Auth0 : détection et réponse

L'Account Takeover est la compromission d'un compte légitime. Stratégies de détection en temps réel et de réponse automatique avec Auth0.

Par Auth0.Expert · 2025-05-01 · 11 min de lecture

ATO Account Takeover Détection

Prévenir l'Account Takeover avec Auth0

TL;DR

L'Account Takeover (ATO) survient quand un attaquant prend le contrôle d'un compte légitime. Les coûts sont énormes : fraude financière, perte de données, dommage réputationnel. Ce guide présente la détection et la réponse automatique.

---

Les vecteurs d'ATO

Avant de protéger vos utilisateurs, il est crucial de comprendre les principales méthodes utilisées par les attaquants pour prendre le contrôle d'un compte.

  1. Credential stuffing : utiliser des mots de passe volés d'autres services
  2. Phishing : voler les credentials via un faux site
  3. SIM swapping : usurper le numéro de téléphone pour le MFA SMS
  4. Session hijacking : voler un cookie ou un token actif
  5. Password reset abuse : exploiter une vulnérabilité dans le reset

---

Détection en temps réel : signaux d'ATO

Ce script Action Post Login Auth0 détecte en temps réel les signaux potentiels d'attaque ATO lors de la connexion utilisateur, en attribuant un score de risque et en adaptant la sécurité (MFA, alerte).

// Action Post Login : score d'anomalie ATO
exports.onExecutePostLogin = async (event, api) => {
  const user = event.user;
  const req = event.request;
  const namespace = 'https://yourapp.com/';

  let atoRisk = 0;
  const signals = [];

  // Signal 1: Changement de pays
  if (user.app_metadata?.last_country &&
      user.app_metadata.last_country !== req.geoip?.country_code) {
    atoRisk += 30;
    signals.push(`country_change:${user.app_metadata.last_country}→${req.geoip?.country_code}`);
  }

  // Signal 2: IP compromise (AbuseIPDB)
  if (req.geoip?.is_tor) {
    atoRisk += 40;
    signals.push('tor_exit_node');
  }

  // Signal 3: Heure inhabituelle pour cet utilisateur
  const loginHour = new Date().getUTCHours();
  const lastHour = user.app_metadata?.typical_login_hour;
  if (lastHour && Math.abs(loginHour - lastHour) > 8) {
    atoRisk += 15;
    signals.push(`unusual_hour:${loginHour}`);
  }

  // Signal 4: Premier login après longue inactivité
  const daysSinceLastLogin = user.last_login
    ? (Date.now() - new Date(user.last_login)) / 86400000
    : 0;
  if (daysSinceLastLogin > 90) {
    atoRisk += 20;
    signals.push(`inactive_${Math.round(daysSinceLastLogin)}d`);
  }

  // Décision basée sur le score
  if (atoRisk >= 60) {
    // Risque élevé : MFA obligatoire + alerte
    api.multifactor.enable('any', { allowRememberBrowser: false });
    await notifySecurityTeam(user.email, atoRisk, signals, req.ip, event.secrets);
  } else if (atoRisk >= 30) {
    // Risque modéré : MFA
    api.multifactor.enable('any');
  }

  // Mettre à jour les données de référence
  api.user.setAppMetadata('last_country', req.geoip?.country_code);
  api.user.setAppMetadata('typical_login_hour', loginHour);

  // Injecter le score dans le token pour l'API
  api.accessToken.setCustomClaim(`${namespace}ato_risk`, atoRisk);
  api.accessToken.setCustomClaim(`${namespace}ato_signals`, signals);
};

async function notifySecurityTeam(email, risk, signals, ip, secrets) {
  await fetch(secrets.SLACK_WEBHOOK, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      text: `🚨 *ATO Risk Alert*
User: ${email}
Score: ${risk}/100
IP: ${ip}
Signals: ${signals.join(', ')}`
    }),
  });
}

Ce code détecte plusieurs comportements anormaux à la connexion pour calculer un score de risque ATO, déclenchant MFA ou une alerte si besoin.

---

Réponse automatique graduée

Cette logique backend applique des actions automatiques selon la gravité du risque ATO, pour limiter l'impact (blocage, reset de mot de passe, suivi).

# Backend : réponse aux alertes ATO basée sur le score
async def handle_auth_event(payload: dict):
    ato_risk = payload.get('https://yourapp.com/ato_risk', 0)
    user_id = payload['sub']

    if ato_risk >= 80:
        # Suspendre immédiatement
        await auth0.block_user(user_id)
        await send_user_email_alert(user_id, 'account_suspended')
        await create_security_incident('ato_high_risk', user_id, ato_risk)

    elif ato_risk >= 50:
        # Forcer reset de mot de passe
        await auth0.trigger_password_reset(user_id)
        await send_user_email_alert(user_id, 'security_review')

    elif ato_risk >= 30:
        # Logger pour analyse ultérieure
        await log_suspicious_activity(user_id, ato_risk)

Ce code prend automatiquement des mesures de sécurité adaptées selon le score de risque de takeover détecté.

---

Détection post-login : activités suspectes

Après la connexion, surveillez les comportements inhabituels pour identifier les attaques ATO potentielles, comme l'export massif de données.

// Surveiller les actions suspectes après login
// (appels API inhabituels, données massives exportées, etc.)

async function checkPostLoginBehavior(accessToken, action) {
  const payload = await verifyToken(accessToken);
  const userId = payload.sub;

  // Vérifier si l'action est normale pour cet utilisateur
  const userHistory = await getUserActionHistory(userId);
  const isUnusual = !userHistory.commonActions.includes(action);

  if (isUnusual && action.startsWith('export:')) {
    // Exporter des données = action sensible inhabituelle
    await createReviewRequest(userId, action);
    await notify_security_team(userId, action);
  }
}

Ce script contrôle s'il y a des actions post-login anormales et alerte votre équipe sécurité si besoin.

---

Honeypot : piéger les attaquants ATO

Créer un compte leurre permet de détecter rapidement un comportement malveillant ciblant vos utilisateurs.

// Créer un "fake account" que seul un attaquant essaierait d'utiliser
// Si quelqu'un se connecte à ce compte → ATO en cours sur votre système

exports.onExecutePostLogin = async (event, api) => {
  const HONEYPOT_EMAILS = ['[email protected]', '[email protected]'];

  if (HONEYPOT_EMAILS.includes(event.user.email)) {
    // Ne jamais bloquer (pour logger l'attaquant)
    // Mais alerter immédiatement
    await fetch(event.secrets.ALERT_WEBHOOK, {
      method: 'POST',
      body: JSON.stringify({
        alert: 'HONEYPOT_LOGIN',
        ip: event.request.ip,
        user_agent: event.request.user_agent,
        timestamp: new Date().toISOString(),
      }),
    });
  }
};

Ce bloc permet d'alerter en temps réel si un attaquant accède à un compte honeypot dédié.

---

Checklist anti-ATO

Pour renforcer la défense globale, voici les bonnes pratiques à appliquer en complément des réponses techniques.

---

> 🚨 Programme ATO : nous déployons un système complet de détection et de réponse ATO adapté à votre secteur (fintech, e-commerce, SaaS).

📧 [email protected]


Autres articles