Identifier ce qu'est réellement un client (navigateur, outil, bot) et détecter quand il ment — en croisant des signaux à plusieurs niveaux (TLS, HTTP, JS, matériel, réseau) qui sont difficiles à falsifier tous en même temps de façon cohérente.
client ──HTTPS:443──▶ HAProxy ──HTTP──▶ Flask
│ termine TLS │ JA4H (HTTP) + analyse
│ calcule le JA4 │ GeoIP/ASN (.mmdb MaxMind)
└ injecte X-JA4 │ sert la page de profilage JS
HTTP:80 ▶ HAProxy ─ ACME ─▶ Flask ; reste ─301─▶ HTTPS
certbot ─ Let's Encrypt (renouvellement auto, reload HAProxy)
Pourquoi HAProxy ? Le JA4 (TLS) se calcule sur le ClientHello — seul le terminateur TLS le voit. Flask est derrière, il ne pourrait jamais le calculer. Plugin Lua : O-X-L/haproxy-ja4-fingerprint.
| Empreinte | Niveau | Falsifiable ? | Ce qu'elle dit |
|---|---|---|---|
| JA4 (TLS) | ClientHello TLS | très dur | la pile TLS du client (ciphers, extensions, ALPN…) |
| JA4H (HTTP) | requête HTTP | moyen | méthode, ordre/jeu des headers, langue, cookies |
| User-Agent | header | trivial | ce que le client prétend être |
Nuance JA4 en TLS 1.3 : la partie b (ciphers, triés) est identique entre Chrome et Firefox → elle ne distingue pas les navigateurs. Le discriminant est la partie c (extensions). C'est pour ça qu'un match sur les ciphers seuls reste « famille indéterminée ».
On déduit l'outil depuis l'empreinte, par ordre de fiabilité : base curée → ja4db.com (match exact) → extensions a_c → ciphers a_b (non nommant). Le moteur de rendu (Gecko/Blink/WebKit) est déduit du UA et par feature-detection JS (bien plus fiable).
| Section | Signaux |
|---|---|
| GPU / écran | WebGL renderer (révèle le chip), résolution, viewport, DPR, profondeur couleur |
| CPU / Architecture | Client Hints (arch/bitness/model) + SoC déduit du GPU. Note : navigator.platform dit « MacIntel » même sur Apple Silicon — non fiable, pas une incohérence. |
| Hardware consistency | device détecté vs profil attendu (device_profiles.json) → incohérences (ex. iPhone avec grand écran, GPU Apple mais arch x86…) |
Intl vs Accept-Language — langue OS réelle vs header déclaréeval.toString().length (V8=33, SpiderMonkey/JSC=37) → confirme le moteur sans faire confiance au UALe navigateur fait un round-trip STUN (Google) qui lui révèle son IP publique, puis la livre au JS via les candidats ICE. On collecte IPv4 + IPv6 (local + public) et on compare l'IP publique fuitée à l'IP vue par le serveur : différentes → derrière un VPN/proxy. Le STUN est public (stun.l.google.com) — configurable.
Canvas · Audio (OfflineAudioContext) · paramètres WebGL · fonts installées → hashés en un composite fingerprint SHA-256 (identifiant client stable même sans cookie).
MD5 → un bot/scraper ne charge pas les images, ou les altère. chargée + MD5 OK = vrai navigateurhardwareConcurrency annoncé → démasque un bot qui ment sur ses cœursnavigator.webdriver, window.chrome manquant, Notification.permission, 0 plugin/0 media device, outerWidth=0…JS hashcash (SHA-256, N bits à zéro → hashrate) et GPU WebGL (fragment-shader lourd → débit + confirme un GPU matériel vs SwiftShader=headless).
Charge déclenche tout le calcul serveur (JA4/JA4H/IP/headers) sans JS, puis renvoie une vraie image. Idéal email/forum/furtif.
<img src="https://TON-DOMAINE/image.png?TOKEN">
Le TOKEN identifie qui a ouvert → relisible via /result/?id=TOKEN.
| Route | Rôle |
|---|---|
GET / | page d'accueil (présentation, login) |
GET /track?id=TOKEN | page de profilage du navigateur (exécute les checks JS) |
GET /app | dashboard (login requis) : créer/supprimer ses tokens, voir les stats |
GET /json | analyse complète en JSON |
GET /image.png?TOKEN | pixel tracker → vraie image (+&transparent=1 pour 1×1) |
GET /pixel.png?TOKEN | pixel 1×1 transparent |
GET /verify.png | image de vérification (anti-bot MD5, sans log) |
GET /result/?id=TOKEN&format=json|html | toutes les requêtes d'un token (timeline). html = page lisible, json = brut |
GET /track?format=jsonashtml | page de test qui exécute le JS puis affiche le JSON complet (serveur + client) |
POST /result/delete?id=TOKEN | supprime toutes les données stockées d'un token |
GET /docs | cette page |
JA4+ : FoxIO-LLC/ja4 · base communautaire ja4db.com.