Saltar al contenido principal
fr/blog/obscura/research/network-fingerprinting/

obscura/research/network-fingerprinting

6 min de lecture

Aperçu

Signaux visibles au niveau TCP/IP et de la couche transport, avant toute exécution HTTP ou JS.


1. Empreinte de Pile TCP/IP (JA4T / Satori / p0f)

Mécanisme

L'empreinte OS passive lit le paquet SYN TCP pour identifier le système d'exploitation. Chaque pile TCP/IP d'OS a une combinaison unique de :

  • TTL initial : 64 (Linux/macOS), 128 (Windows), 255 (Certains UNIX)
  • Taille de fenêtre : 64240 (Chrome/Linux), 65535 (macOS), 8192 (systèmes plus anciens)
  • MSS (Taille Maximale de Segment) : Dérivé du MTU
  • Options TCP : Ordre et sélection de MSS, SACK_PERM, TIMESTAMP, NOP, WINDOW_SCALE
  • Drapeaux IP : Comportement du bit DF (Ne Pas Fragmenter)

Formats

JA4T : 64240_2-4-8-1-3_1452_10

Composant Signification Exemple
64240 Taille de Fenêtre TCP Défaut Windows
2-4-8-1-3 Ordre des options TCP (MSS, SACK, TIMESTAMP, NOP, WINDOW) Ordre Chrome/Linux
1452 MSS Dérivé du MTU
10 Compteur de décalage de fenêtre Multiplicateur 2^10 = 1024

Empreinte Satori : 64240:64:1:60:M1452,S,T,N,W10:.

Détection OS

OS Fenêtre TTL MSS Options
Linux 29200-65535 64 1460 M,S,T,N,W(7-8)
Windows 10/11 64240 128 1460 M,S,T,N,W(10)
macOS 65535 64 1460 M,S,T,N,W(6-7)
Android 29200-65535 64 1460 M,S,T,N,W(7-8)

Impact sur Obscura

Client  Conteneur Obscura (terminaison TCP)  Internet
                                      
     Pile TCP client            Pile TCP du conteneur
     (visible par Obscura)      (visible par la destination)

Le serveur de destination voit la pile TCP d'Obscura, pas celle du client. C'est inévitable car le conteneur termine la connexion TCP du client.

Atténuation : Aucune au niveau TCP. Cependant, la plupart des services d'empreinte se concentrent sur les empreintes au niveau application (TLS, HTTP) plutôt qu'au niveau TCP. L'empreinte TCP seule identifie rarement un utilisateur.


2. Empreinte TLS (JA3 / JA4)

Voir tls-fingerprinting.md pour tous les détails.

Points clés pour la couche réseau :

  • La poignée de main TLS est le signal réseau le plus important
  • Entièrement contrôlable via utls (Go) ou Rust TLS personnalisé
  • Critique pour Obscura — doit usurper ou le proxy est révélé

3. Empreinte HTTP/2

Mécanisme

La préface de connexion HTTP/2 et les trames initiales varient selon l'implémentation.

Signaux :

  • Paramètres de trame SETTINGS (l'ordre compte) :
    • SETTINGS_HEADER_TABLE_SIZE
    • SETTINGS_ENABLE_PUSH
    • SETTINGS_MAX_CONCURRENT_STREAMS
    • SETTINGS_INITIAL_WINDOW_SIZE
    • SETTINGS_MAX_FRAME_SIZE
    • SETTINGS_MAX_HEADER_LIST_SIZE
  • Trame initiale WINDOW_UPDATE
  • Comportement PING
  • Structure des trames PRIORITY

Exemples par Navigateur

Navigateur Fenêtre Initiale Max Concurrents Taille Table d'En-têtes
Chrome 6291456 1000 65536
Firefox 131072 100 65536
Safari 1048576 100 65536

Impact sur Obscura

Si Go net/http est utilisé pour HTTP/2, le serveur voit l'empreinte HTTP/2 de Go. Doit implémenter HTTP/2 personnalisé ou utiliser une bibliothèque qui permet la surcharge des SETTINGS.


4. Empreinte QUIC / HTTP/3

Problème

HTTP/3 fonctionne sur QUIC (UDP). Les connexions QUIC sont chiffrées de bout en bout, y compris la couche transport :

Client  QUIC (UDP 443)  Serveur
                          
     Chiffré            Chiffré
     (ne peut inspecter) (ne peut inspecter)

Les paramètres de transport QUIC, les ID de connexion et les informations de version sont visibles dans la poignée de main initiale, mais le proxy ne peut pas les modifier.

Stratégie

Bloquer UDP 443 pour forcer le repli vers HTTP/2 ou HTTP/1.1 sur TCP :

iptables -A FORWARD -p udp --dport 443 -j DROP

Cela empêche les connexions QUIC de contourner le proxy.

Compromis : Latence légèrement plus élevée (TCP vs QUIC), pas de 0-RTT, pas de migration de connexion.


5. Empreintes Basées sur le Temps

5.1 Chronométrage de Performance

performance.now()  // Horodatage haute résolution en ms (précision sub-milliseconde)
performance.timeOrigin
performance.getEntriesByType('navigation')

Atténuation : Arrondir performance.now() à une résolution de 100ms via injection JS :

const originalNow = performance.now.bind(performance)
performance.now = () => Math.round(originalNow() / 100) * 100

5.2 Dérive d'Horloge

Les serveurs peuvent mesurer la dérive d'horloge en comparant les valeurs Date.now() entre les requêtes.

Atténuation : Arrondir la résolution de Date.now().

5.3 Chronométrage Réseau via Chargement de Ressources

Les sites mesurent la latence en chronométrant le temps de chargement des ressources :

const start = performance.now()
fetch('/image.png').then(() => {
  const rtt = performance.now() - start
})

Atténuation : Ne peut pas être totalement empêché — le proxy ajoute sa propre latence mais le timing relatif fuit encore des informations.


6. Fuite IP WebRTC

Mécanisme

WebRTC contourne le proxy en utilisant des serveurs STUN/TURN pour découvrir la véritable IP.

const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
})
pc.createDataChannel('test')
pc.createOffer().then(d => pc.setLocalDescription(d))
pc.onicecandidate = e => {
  if (e.candidate) {
    // e.candidate.candidate contient l'adresse IP
    console.log(e.candidate.candidate)
  }
}

Atténuation via Injection JS

// Bloquer WebRTC complètement
Object.defineProperty(window, 'RTCPeerConnection', { value: undefined })
Object.defineProperty(window, 'RTCDataChannel', { value: undefined })
Object.defineProperty(window, 'RTCSessionDescription', { value: undefined })

Effet

Paramètre Fuite WebRTC Détection
WebRTC disponible IP fuit Non détecté
WebRTC bloqué Pas de fuite Détectable (absence de fonctionnalité)

7. Empreinte DNS

Signaux

  • IP du résolveur DNS (Cloudflare 1.1.1.1 vs Google 8.8.8.8 vs FAI)
  • DNS sur HTTPS vs DNS sur TLS vs DNS standard
  • Sous-réseau client EDNS0 (révèle l'emplacement réseau approximatif)
  • Support DNSSEC

Atténuation

Obscura contrôle complètement le DNS. Utiliser un amont cohérent et axé sur la confidentialité (Quad9 9.9.9.9 ou Cloudflare 1.1.1.1) et supprimer le sous-réseau client EDNS0.


Conclusions pour Obscura

Vecteur Contrôlable Priorité Notes
Empreinte TCP/IP Non (héritée du conteneur) Faible Faible entropie, rarement utilisé seul
Empreinte TLS Oui (via utls) Critique Doit usurper ou le proxy est révélé
Empreinte HTTP/2 Partiel Moyenne Nécessite implémentation HTTP/2 personnalisée
QUIC/HTTP/3 Bloque ou hérite Moyenne Bloquer UDP 443
Attaques temporelles Partiel Faible Arrondir performance.now()
Fuite IP WebRTC Oui (bloquer via JS) Élevée Critique pour les utilisateurs VPN
Empreinte DNS Oui Élevée Obscura contrôle le DNS