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

obscura/research/network-fingerprinting

5 Min. Lesezeit

Übersicht

Signale, die auf TCP/IP- und Transportebene sichtbar sind, vor jeder HTTP- oder JS-Ausführung.


1. TCP/IP-Stack-Fingerprint (JA4T / Satori / p0f)

Mechanismus

Passives OS-Fingerprinting liest das TCP-SYN-Paket, um das Betriebssystem zu identifizieren. Jeder OS-TCP/IP-Stack hat eine einzigartige Kombination aus:

  • Initialer TTL: 64 (Linux/macOS), 128 (Windows), 255 (manche UNIX)
  • Fenstergröße: 64240 (Chrome/Linux), 65535 (macOS), 8192 (ältere Systeme)
  • MSS (Maximum Segment Size): Abgeleitet von der MTU
  • TCP-Optionen: Reihenfolge und Auswahl von MSS, SACK_PERM, TIMESTAMP, NOP, WINDOW_SCALE
  • IP-Flags: DF (Don't Fragment)-Bit-Verhalten

Formate

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

Komponente Bedeutung Beispiel
64240 TCP-Fenstergröße Windows-Standard
2-4-8-1-3 TCP-Optionsreihenfolge (MSS, SACK, TIMESTAMP, NOP, WINDOW) Chrome/Linux-Reihenfolge
1452 MSS Abgeleitet von MTU
10 Window-Scale-Shift-Zähler 2^10 = 1024 Multiplikator

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

OS-Erkennung

OS Fenster TTL MSS Optionen
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)

Auswirkung auf Obscura

Client  Obscura-Container (TCP-Terminierung)  Internet
                                      
     Client-TCP-Stack            Container-TCP-Stack
     (für Obscura sichtbar)      (für Ziel sichtbar)

Der Zielserver sieht Obscuras TCP-Stack, nicht den des Clients. Dies ist unvermeidbar, da der Container die Client-TCP-Verbindung terminiert.

Abschwächung: Keine auf TCP-Ebene. Die meisten Fingerprinting-Dienste konzentrieren sich jedoch auf Anwendungsebene (TLS, HTTP) statt auf TCP-Ebene. Der TCP-Fingerprint allein identifiziert selten einen Benutzer.


2. TLS-Fingerprint (JA3 / JA4)

Siehe tls-fingerprinting.md für vollständige Details.

Wichtige Punkte für die Netzwerkschicht:

  • Der TLS-Handshake ist das wichtigste Signal auf Netzwerkebene
  • Vollständig kontrollierbar via utls (Go) oder eigenem Rust-TLS
  • Kritisch für Obscura – muss gespooft werden, sonst wird der Proxy verraten

3. HTTP/2-Fingerprint

Mechanismus

Die HTTP/2-Verbindungspräambel und die ersten Frames variieren je nach Implementierung.

Signale:

  • SETTINGS-Frame-Parameter (Reihenfolge ist wichtig):
    • SETTINGS_HEADER_TABLE_SIZE
    • SETTINGS_ENABLE_PUSH
    • SETTINGS_MAX_CONCURRENT_STREAMS
    • SETTINGS_INITIAL_WINDOW_SIZE
    • SETTINGS_MAX_FRAME_SIZE
    • SETTINGS_MAX_HEADER_LIST_SIZE
  • WINDOW_UPDATE-Initial-Frame
  • PING-Verhalten
  • PRIORITY-Frame-Struktur

Browser-Beispiele

Browser Initial Window Max Concurrent Header Table Size
Chrome 6291456 1000 65536
Firefox 131072 100 65536
Safari 1048576 100 65536

Auswirkung auf Obscura

Bei Verwendung von Go's net/http für HTTP/2 sieht der Server Go's HTTP/2-Fingerprint. Eigenes HTTP/2 muss implementiert oder eine Bibliothek verwendet werden, die SETTINGS-Überschreibung erlaubt.


4. QUIC / HTTP/3-Fingerprint

Problem

HTTP/3 läuft über QUIC (UDP). QUIC-Verbindungen sind Ende-zu-Ende verschlüsselt, einschließlich der Transportschicht:

Client  QUIC (UDP 443)  Server
                          
    Verschlüsselt        Verschlüsselt
    (kann nicht prüfen)  (kann nicht prüfen)

QUIC-Transportparameter, Verbindungs-IDs und Versionsinformationen sind im initialen Handshake sichtbar, aber der Proxy kann sie nicht ändern.

Strategie

UDP 443 blockieren, um einen Fallback auf HTTP/2 oder HTTP/1.1 über TCP zu erzwingen:

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

Dies verhindert, dass QUIC-Verbindungen den Proxy umgehen.

Zielkonflikt: Etwas höhere Latenz (TCP vs. QUIC), kein 0-RTT, keine Verbindungsmigration.


5. Zeitbasierte Fingerprints

5.1 Performance-Timing

performance.now()  // Hochauflösender Zeitstempel in ms (Sub-Millisekunden-Präzision)
performance.timeOrigin
performance.getEntriesByType('navigation')

Abschwächung: performance.now() auf 100 ms Auflösung runden per JS-Injection:

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

5.2 Clock Skew

Server können den Clock Skew messen, indem sie Date.now()-Werte über mehrere Anfragen vergleichen.

Abschwächung: Date.now()-Auflösung runden.

5.3 Netzwerk-Timing via Ressourcenladung

Websites messen die Latenz, indem sie die Ladezeit von Ressourcen messen:

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

Abschwächung: Kann nicht vollständig verhindert werden – der Proxy fügt seine eigene Latenz hinzu, aber das relative Timing gibt weiterhin Informationen preis.


6. WebRTC-IP-Leck

Mechanismus

WebRTC umgeht den Proxy, indem es STUN/TURN-Server verwendet, um die echte IP zu ermitteln.

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 enthält IP-Adresse
    console.log(e.candidate.candidate)
  }
}

Abschwächung per JS-Injection

// WebRTC vollständig blockieren
Object.defineProperty(window, 'RTCPeerConnection', { value: undefined })
Object.defineProperty(window, 'RTCDataChannel', { value: undefined })
Object.defineProperty(window, 'RTCSessionDescription', { value: undefined })

Wirkung

Einstellung WebRTC-Leck Erkennung
WebRTC verfügbar IP-Leck Nicht erkannt
WebRTC blockiert Kein Leck Erkennbar (Feature-Abwesenheit)

7. DNS-Fingerprint

Signale

  • DNS-Resolver-IP (Cloudflare 1.1.1.1 vs. Google 8.8.8.8 vs. ISP)
  • DNS over HTTPS vs. DNS over TLS vs. normales DNS
  • EDNS0-Client-Subnetz (verrät ungefähren Netzwerkstandort)
  • DNSSEC-Unterstützung

Abschwächung

Obscura kontrolliert DNS vollständig. Verwende einen konsistenten, datenschutzfreundlichen Upstream (Quad9 9.9.9.9 oder Cloudflare 1.1.1.1) und entferne EDNS0-Client-Subnetz.


Schlussfolgerungen für Obscura

Vektor Kontrollierbar Priorität Anmerkungen
TCP/IP-Fingerprint Nein (vom Container geerbt) Niedrig Niedrige Entropie, selten allein verwendet
TLS-Fingerprint Ja (via utls) Kritisch Muss gespooft werden, sonst wird Proxy verraten
HTTP/2-Fingerprint Teilweise Mittel Erfordert eigene HTTP/2-Implementierung
QUIC/HTTP/3 Blockieren oder erben Mittel UDP 443 blockieren
Timing-Angriffe Teilweise Niedrig performance.now() runden
WebRTC-IP-Leck Ja (per JS blockieren) Hoch Kritisch für VPN-Benutzer
DNS-Fingerprint Ja Hoch Obscura kontrolliert DNS