Explorer
KNOW-PAT-053

Système de blacklist avec scoring de risque comportemental (WooCommerce)

Domaine
cybersecu
Type
pattern
Priorité
P2

Parent : [[INDEX-CYBERSECU]]

Système de blacklist avec scoring de risque comportemental (WooCommerce)

Problème

L'archive Ygg contient un système de blacklist intégré à WooCommerce avec scoring de risque basé sur le comportement utilisateur. Le script analyse les logs de checkout pour détecter les emails suspects (multi-pays, multi-navigateurs, pas de langue FR). L'API de blacklist a une clé hardcodée (YGG_BLACKLIST_API_KEY_2024).

Contexte archive Ygg

  • Scripts : 06f_blacklist/analysis/risk_analysis.py, blacklist_api.py
  • Source : Logs WooCommerce checkout_access.log
  • API : https://www.yggtorrent.top/api/blacklist_user
  • Clé API : YGG_BLACKLIST_API_KEY_2024 (hardcodée)

Technique du système

1. Scoring de risque (risk_analysis.py)

Le script analyse chaque email sur 4 axes (score 0-100) :

Critère Seuil Points Rationale
Langue FR absente has_french_lang = False +30 Cible non francophone = suspect pour site FR
Multi-navigateurs ≥4 browsers +25 Partage de compte ou bot
Ratio IP/accès >0.8 +20 VPN switching agressif
Volume d'accès ≥50 +25 Usage automatisé

Décision :

  • ≥70 : CRITIQUE (blacklist immédiat)
  • ≥50 : ÉLEVÉ (review manuel)
  • ≥30 : MODÉRÉ (flag pour monitoring)

2. API de blacklist (blacklist_api.py)

API_URL = "https://www.yggtorrent.top/api/blacklist_user"
API_KEY = "YGG_BLACKLIST_API_KEY_2024"  # HARDCODED

Envoi POST avec rate limiting (1 req/sec) et queue threadée.

Solution protectif — Système de fraud detection sécurisé

1. Architecture de scoring

# fraud_detector.py — Système de scoring générique
from dataclasses import dataclass
from enum import Enum
from typing import Set

class RiskLevel(Enum):
    LOW = (0, 30, "green")
    MODERATE = (30, 50, "yellow")
    HIGH = (50, 70, "orange")
    CRITICAL = (70, 100, "red")

@dataclass
class UserProfile:
    email: str
    access_count: int
    ips: Set[str]
    countries: Set[str]
    browsers: Set[str]
    languages: Set[str]
    
class FraudDetector:
    def __init__(self, config: dict):
        self.rules = config.get('rules', [])
        self.thresholds = config.get('thresholds', {
            'critical': 70,
            'high': 50,
            'moderate': 30
        })
    
    def calculate_score(self, profile: UserProfile) -> tuple[int, list]:
        score = 0
        reasons = []
        
        # Règle configurable : langue attendue
        expected_lang = self.rules.get('expected_language', 'fr')
        if expected_lang not in profile.languages:
            score += 30
            reasons.append(f"Langue '{expected_lang}' absente")
        
        # Règle : multi-navigateurs
        if len(profile.browsers) >= 4:
            score += 25
            reasons.append(f"{len(profile.browsers)} navigateurs détectés")
        
        # Règle : ratio IP/accès
        ratio = len(profile.ips) / profile.access_count if profile.access_count > 0 else 0
        if ratio > 0.8:
            score += 20
            reasons.append(f"Ratio IP/accès élevé: {ratio:.2f}")
        
        # Règle : volume
        if profile.access_count >= 50:
            score += 25
            reasons.append(f"Volume anormal: {profile.access_count} accès")
        
        return min(score, 100), reasons

2. API sécurisée (PAS de clé hardcodée)

# blacklist_api.py — API avec gestion de secrets
import os
from functools import wraps

class BlacklistAPI:
    def __init__(self):
        self.api_url = os.getenv('BLACKLIST_API_URL')
        self.api_key = os.getenv('BLACKLIST_API_KEY')
        
        if not self.api_url or not self.api_key:
            raise ValueError("BLACKLIST_API_URL et BLACKLIST_API_KEY requis")
    
    def blacklist_email(self, email: str, reason: str, score: int) -> bool:
        headers = {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {self.api_key}',
            'X-Request-ID': generate_uuid()  # Traçabilité
        }
        
        payload = {
            'email': email,
            'reason': reason,
            'risk_score': score,
            'timestamp': datetime.utcnow().isoformat()
        }
        
        # Audit log avant action
        audit_log.info(f"Blacklist request: {email}, score={score}, reason={reason}")
        
        response = requests.post(
            self.api_url,
            headers=headers,
            json=payload,
            timeout=30
        )
        
        if response.status_code == 200:
            audit_log.info(f"Blacklist success: {email}")
            return True
        else:
            audit_log.error(f"Blacklist failed: {email}, status={response.status_code}")
            return False

3. Protection contre les faux positifs

  • Review manuel pour scores 30-70
  • Double confirmation pour score >70 (2 analystes)
  • Whitelist : emails vérifiés (KYC, anciens clients)
  • Appel : contacter l'utilisateur avant blacklist

Checklist de validation

  • Clé API dans variable d'environnement (jamais hardcodée)
  • Audit log de chaque décision de blacklist
  • Review manuel avant action irréversible
  • Règles de scoring configurables (pas de "langue FR" en dur)
  • Faux positifs trackés et corrigés
  • Rate limiting sur l'API (pas de spam)
  • Authentification Bearer (pas x-api-key simple)

Anti-pattern associé

  • KNOW-ANT-002 — Clés d'accès hardcodées

Comment se prot[ée]ger

  • Rate limiting adaptatif bas[ée] sur le score de risque
  • CAPTCHA pour les requ[ê]tes [a] risque [[ee]lev[ee]
  • Monitoring des patterns d'abus (burst, distributed)
  • Whitelist IP pour les partenaires de confiance
  • Alerting automatique sur seuil de blacklist

Références

  • Archive Ygg : 06f_blacklist/analysis/risk_analysis.py, blacklist_api.py
  • Archive Ygg : 06f_blacklist/checkout_access.log
  • OWASP : Fraud Detection Best Practices