BotDetect v2 — Bibliothèque de détection de robots en production
Bibliothèque de détection de robots et d'automatisation côté client avec score pondéré, analyse comportementale, empreinte numérique du navigateur et seuils configurables. Détecte les navigateurs sans tête, Selenium, Puppeteer, Playwright, les outils basés sur CDP et les frameworks d'automatisation furtifs.
v2.1.0 — pots de miel anti-détection, empreinte canvas stable sur GPU, analyse comportementale améliorée, initialisation paresseuse, détection de falsification côté serveur, liaison d'empreinte de requête, et limitation de débit.
Table des matières
Fonctionnalités
- 28 modules de détection couvrant les frameworks d'automatisation, les navigateurs sans tête, l'empreinte numérique, l'analyse comportementale, les pots de miel et les pièges de trace de pile
- Système de score pondéré — chaque signal a un poids configurable ; le score final est calculé côté serveur
- Trois niveaux de verdict :
humain, suspect, robot avec des actions de friction correspondantes (surveiller, défier, bloquer)
- Vérification côté serveur — protégée par nonce, contre la relecture, signée par preuve de travail
- Pièges de trace de pile — modifie les API DOM pour capturer les appels de pile des outils d'automatisation
- Analyse comportementale — courbure de la souris, variance temporelle des frappes, accélération du défilement, dynamique tactile
- Pots de miel anti-détection — masquage CSS aléatoire, champs leurres, noms de champs réalistes
- Détection de falsification côté serveur — valide l'intégrité des signaux, détecte les tentatives de triche
- Liaison d'empreinte de requête — jetons PoW liés aux attributs de la requête HTTP
- Limitation de débit — limitation de débit par session sur tous les points de terminaison de vérification
- Détection sans script — identifie les clients qui n'envoient jamais de charges utiles de détection
- Liste blanche de robots connus — 20+ robots légitimes exclus du score
Architecture
Navigateur Votre Serveur
┌──────────────────────────────┐ ┌──────────────────────────┐
│ Collecteur (singleton) │ POST │ Middleware Express │
│ ├─ 28 modules de détection │ signaux │ ├─ GestionnaireNonce │
│ ├─ SuiviComportemental │ + nonce │ ├─ LimiteurDébit │
│ ├─ PiègesPotMiel │───────────▶│ ├─ DétecteurFalsification│
│ ├─ PiègesTracePile │ │ ├─ calculerVerdict() │
│ └─ ContexteIframe │ │ └─ Preuve-de-Travail │
│ │ verdict │ │
│ ↓ collect() → │ + preuve │ Retourne : │
│ DetectionResult[] │◀───────────│ { verdict, score, │
└──────────────────────────────┘ │ confiance, preuve, │
│ scoreFalsification } │
└──────────────────────────┘
│
▼
Point de terminaison
protégé par session
(connexion, paiement, etc.)
valide la preuve avant
d'accorder l'accès
Principe clé : Le navigateur collecte uniquement les signaux bruts DetectionResult[]. Le serveur calcule le verdict final à l'aide d'une table de poids secrète. Les verdicts calculés par le client ne sont jamais fiables.
Démarrage rapide
1. Construire
npm install
npm run build
Produit dans dist/ :
botdetect.min.js (avec polyfills, ~151 Ko)
botdetect-clean.min.js (navigateurs modernes uniquement, ~74 Ko)
2. Inclure sur votre page
<script src="/chemin/vers/botdetect.min.js"></script>
<script>
BotDetect.collector.enableTraps();
BotDetect.collector.enableBehavioralTracking();
BotDetect.collector.enableHoneypots();
</script>
cd server
npm install express cors express-session
node example-integration.js
4. Envoyer les signaux lors d'une action sensible
async function onLogin() {
const { nonce } = await (await fetch('/api/botdetect/nonce')).json();
BotDetect.collector.setNonce(nonce);
const signals = await BotDetect.collector.collect();
const resp = await fetch('/api/botdetect/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ signals, nonce })
});
const { verdict, score, proof, friction } = await resp.json();
document.getElementById('botdetect-proof').value = proof;
document.getElementById('login-form').submit();
}
5. Valider sur le serveur
app.post('/api/login', (req, res) => {
const bd = req.session.botdetect;
if (!bd) return res.status(403).json({ error: 'no_verification' });
if (bd.verdict === 'bot') return res.status(403).json({ error: 'access_denied' });
if (bd.verdict === 'suspicious') return challengeCaptcha(req, res);
res.json({ success: true });
});
API côté client
Collecteur (singleton)
import Collector from './collector/Collector';
// ou via global : BotDetect.collector
Détecteur (débogage uniquement)
import Detector from './detector/Detector';
Avertissement : analyze() s'exécute entièrement dans le navigateur. N'utilisez jamais sa sortie pour des décisions de production.
Types
interface DetectionResult {
name: string; // Nom du module
score: number; // 0.0 – 1.0
weight: number; // 1 – 10 (importance)
detail?: string; // Description lisible par un humain
}
interface DetectionVerdict {
verdict: 'bot' | 'suspicious' | 'human';
score: number; // 0.0 – 1.0
confidence: number; // 0.0 – 1.0
signals: DetectionResult[];
threshold: number;
friction: 'monitor' | 'challenge' | 'block';
}
interface CollectorConfig {
detectionTimeoutMs: number; // délai d'attente par module (défaut : 3000)
enableTraps: boolean;
enableBehavioralTracking: boolean;
enableHoneypots: boolean;
thresholds: { strict: number; balanced: number; relaxed: number };
}
Intégration côté serveur
Middleware Express
const { createBotDetectEndpoint } = require('./server');
const { router, generateProofOfWork, cleanup } = createBotDetectEndpoint({
secretSalt: process.env.BOTDETECT_SALT,
scoring: {
threshold: 'balanced', // 'strict' | 'balanced' | 'relaxed' | number
minSignals: 2,
signalBoostThreshold: 0.8,
frictionThresholds: { monitor: 0.2, challenge: 0.5, block: 0.8 }
},
nonce: { ttl: 300000 }, // expiration du nonce après 5 minutes
noScript: { timeout: 10000 }, // fenêtre sans script de 10 s
rateLimit: { maxRequests: 10, windowMs: 60000 },
noScriptPaths: ['/api/login', '/api/checkout', '/api/register']
});
app.use('/api', router);
Points de terminaison
| Point de terminaison | Méthode | Objectif |
|---|
/api/botdetect/nonce |
{
"verdict": "human",
"score": 0.125,
"confidence": 0.85,
"tamperScore": 0,
"friction": "monitor",
"threshold": 0.5,
"proof": "a1b2c3d4e5f6..."
}
Score côté serveur (Node.js)
const { computeVerdict, RateLimiter, NonceManager } = require('./scoring');
const verdict = computeVerdict(signals, {
threshold: 'balanced',
minSignals: 2,
signalBoostThreshold: 0.8,
frictionThresholds: { monitor: 0.2, challenge: 0.5, block: 0.8 }
});
// verdict.tamperScore > 0 si falsification de signal détectée
Modules de détection
Frameworks d'automatisation (poids 5–7)
Spécifiques à Playwright (poids 3–4)
| Module | Détecte | Poids |
|---|
playwrightWebKit | Artefacts d'automatisation WebKit | 4 |
playwrightOrientation | Incohérence orientation + chrome.runtime | 3 |
Analyse comportementale (poids 7)
| Module | Signaux analysés | Poids |
|---|
behavioralAnalysis | Courbure de la souris + rapport ligne droite, CV des frappes + schémas de rafales + KPM, accélération du défilement + changements de direction, variance de force tactile + rayon | 7 |
Empreinte numérique du navigateur (poids 3–4)
Propriétés Navigateur & OS (poids 5)
| Module | Vérifie | Poids |
|---|
navigatorInconsistencies | 11 vérifications : languages, plugins, mimeTypes, platform, UA, cookies, DNT, touch, hardwareConcurrency, deviceMemory, connection | 5 |
Pièges actifs & Pots de miel (poids 8–9)
| Module | Détecte | Poids |
|---|
honeypotTraps | Champs cachés aléatoires + leurres + point de terminaison canari |
Réseau & Contextuel (poids 1–2)
Liste blanche (poids 0)
| Module | Détecte | Poids |
|---|
verifiedBots | 20+ robots connus (Googlebot, Bingbot, Yandex, Facebook, Twitter, etc.) — retourne -1, exclus du score | 0 |
Configuration
Collecteur
const collector = Collector.getInstance({
detectionTimeoutMs: 1000, // Plus bas pour une UX plus rapide
enableTraps: true,
enableBehavioralTracking: true,
enableHoneypots: true,
thresholds: {
strict: 0.3, // Agressif (connexion, paiement)
balanced: 0.5, // Défaut
relaxed: 0.7 // Permissif (navigation de contenu)
}
});
Détecteur (débogage uniquement)
const detector = Detector.getInstance({
threshold: 'balanced', // 'strict' | 'balanced' | 'relaxed' | number
minSignals: 2, // Nombre minimum de signaux avant boost
signalBoostThreshold: 0.8, // Les signaux au-dessus de ce seuil reçoivent un poids supplémentaire
failPolicy: 'open', // 'open' = humain en cas d'erreur, 'closed' = robot en cas d'erreur
frictionThresholds: {
monitor: 0.2,
challenge: 0.5,
block: 0.8
}
});
Serveur
createBotDetectEndpoint({
secretSalt: process.env.BOTDETECT_SALT, // Garder secret
scoring: { threshold: 'balanced' },
nonce: { ttl: 300000, cleanupInterval: 60000 },
noScript: { timeout: 10000 },
rateLimit: { maxRequests: 10, windowMs: 60000 },
requestFingerprint: true, // Lier PoW aux attributs de la requête
noScriptPaths: ['/api/login', '/api/checkout']
});
Liste de vérification pour la production
Sécurité
Surveillance
Tests
npm test # 74 tests Jest répartis sur 6 suites
npm run typecheck # Mode strict TypeScript
npm run lint # ESLint
npm run build # Bundle de production Webpack
Licence
Apache — Lahmeri Mohamed Amine