
Ein lokaler MITM-Proxy, mit dem du TLS-Fingerprints (JA3/JA4), HTTP/2-Fingerprints, die HTTP-Header-Reihenfolge und den User-Agent steuern kannst — alles aus einer einzigen YAML-Konfigurationsdatei.
Ein lokaler MITM-Proxy, mit dem Sie TLS-Fingerabdrücke (JA3/JA4), HTTP/2-Fingerabdrücke, HTTP-Header-Reihenfolge, User-Agent und Quell-IP-Header steuern können – alles aus einer einzigen YAML-Konfigurationsdatei.
Eine Chrome-Erweiterung ist enthalten, mit der Sie den Proxy umschalten und Fingerabdruck-Profile direkt über die Browser-Symbolleiste wechseln können, ohne den Proxy neu zu starten.
Gedacht für autorisierte Sicherheitstests von WAF-Bot-Erkennungssystemen. Leiten Sie curl, Browser oder Playwright durch den Proxy, um zu beobachten, wie verschiedene Fingerabdruck-Kombinationen klassifiziert werden.
curl / browser / Playwright
│ HTTP CONNECT (to proxy)
▼
┌─────────────────────────────────────────┐
│ impersonate-proxy │
│ │
│ MITM TLS ◄──────────────► uTLS │
│ (our CA cert) (custom JA3/4) │
│ │
│ Header rewriter (UA, order, add/del) │
│ HTTP/2 framer (SETTINGS, WINDOW_UPDATE│
│ pseudo-header order) │
└─────────────────────────────────────────┘
│ Custom TLS ClientHello + HTTP/2
▼
Target server / WAF
| Ebene | Was Sie steuern können |
|---|---|
| TLS | Cipher Suites, Erweiterungen und deren Reihenfolge (JA3 / JA4) über uTLS-Presets oder eine vollständig benutzerdefinierte -Spezifikation |
brew install go
Das in der Distribution enthaltene Go ist oft veraltet. Installieren Sie die offizielle Binärdatei direkt:
# Download and extract (replace 1.22.5 with the latest from https://go.dev/dl/)
curl -OL https://go.dev/dl/go1.22.5.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.22.5.linux-amd64.tar.gz
# Add to PATH (add this line to ~/.bashrc or ~/.zshrc to make it permanent)
export PATH=$PATH:/usr/local/go/bin
Überprüfen:
go version
# go version go1.22.5 linux/amd64
ARM64 (Raspberry Pi, AWS Graviton usw.): Ersetzen Sie
linux-amd64im Download-Link durchlinux-arm64.
git clone https://github.com/ytkoka/impersonate-proxy.git
cd impersonate-proxy
make build
Die CA wird beim ersten Start automatisch erzeugt. Starten Sie den Proxy einmal, um ca.crt und ca.key zu erstellen:
make run
# 2026/04/22 12:00:00 generated CA certificate → ca.crt
# 2026/04/22 12:00:00 listening on 127.0.0.1:8080 preset=chrome
Beenden Sie ihn mit Ctrl-C.
Clients müssen Ihrer MITM-CA vertrauen, damit sie die vom Proxy erzeugten Blattzertifikate nicht ablehnen.
macOS-Systemschlüsselbund (betrifft alle Apps):
make trust-ca # runs: sudo security add-trusted-cert ...
Linux-Systemvertrauen (betrifft alle Apps; erfordert das Paket ca-certificates):
# Debian / Ubuntu
sudo cp ca.crt /usr/local/share/ca-certificates/impersonate-proxy.crt
sudo update-ca-certificates
# RHEL / Fedora / Amazon Linux
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/impersonate-proxy.crt
sudo update-ca-trust
Nur curl (keine systemweite Änderung):
curl --cacert ca.crt ...
Playwright / Node.js:
export NODE_EXTRA_CA_CERTS="$(pwd)/ca.crt"
Firefox: Einstellungen → Datenschutz & Sicherheit → Zertifikate anzeigen → Behörden → ca.crt importieren
Bearbeiten Sie config.yaml, bevor Sie den Proxy starten. Alle Felder haben Standardwerte – Sie müssen nur angeben, was Sie überschreiben möchten.
listen: "127.0.0.1:8080"
mgmt_listen: "127.0.0.1:8081" # management API used by the Chrome extension (empty to disable)
ca_cert: "ca.crt"
ca_key: "ca.key"
tls:
# TLS fingerprint preset (controls JA3 / JA4)
# Options: chrome | firefox | safari | edge | ios | random | golang
preset: "chrome"
http:
# Override User-Agent (leave empty to pass through the client's UA)
user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
# Spoof source IP: sets both X-Forwarded-For and True-Client-IP to this value,
# replacing any values the client may have already set (leave empty to disable)
# client_ip: "1.2.3.4"
# Emit headers in this order; headers not listed are appended after
header_order:
- "Host"
- "User-Agent"
- "Accept"
- "Accept-Language"
- "Accept-Encoding"
- "Connection"
# Add or overwrite headers
add_headers:
Accept-Language: "ja,en-US;q=0.9,en;q=0.8"
# Remove headers before forwarding
remove_headers: []
http2:
enabled: true
# SETTINGS frame entries — id and order both affect the HTTP/2 fingerprint.
# RFC 7540 §11.3 IDs:
# 1=HEADER_TABLE_SIZE 2=ENABLE_PUSH 3=MAX_CONCURRENT_STREAMS
# 4=INITIAL_WINDOW_SIZE 5=MAX_FRAME_SIZE 6=MAX_HEADER_LIST_SIZE
settings:
- { id: 1, val: 65536 } # Chrome defaults shown here
- { id: 2, val: 0 }
- { id: 4, val: 6291456 }
- { id: 6, val: 262144 }
# Connection-level WINDOW_UPDATE increment
window_update: 15663105
# Order of pseudo-headers in the HEADERS frame
pseudo_header_order: [method, authority, scheme, path]
Beim Start stellt der Proxy zusätzlich eine schlanke HTTP-API auf mgmt_listen bereit (Standard 127.0.0.1:8081). Die Chrome-Erweiterung nutzt diese, um Einstellungen zur Laufzeit zu lesen und zu aktualisieren, ohne den Proxy neu zu starten. Sie können sie auch direkt mit curl aufrufen:
| Endpoint | Methode | Beschreibung |
|---|---|---|
/api/config | GET |
# Read current settings
curl http://127.0.0.1:8081/api/config
# Switch to Firefox fingerprint and set a spoofed IP
curl -s -X POST http://127.0.0.1:8081/api/config \
-H "Content-Type: application/json" \
-d '{"tls_preset":"firefox","client_ip":"203.0.113.1","user_agent":""}'
# Switch to an arbitrary JA3/JA4 fingerprint at runtime — same fields as the
# config.yaml custom_hello block, sent as JSON (see "Custom TLS fingerprint" below)
curl -s -X POST http://127.0.0.1:8081/api/config \
-H "Content-Type: application/json" \
-d '{
"tls_preset": "custom",
"custom_hello": {
"cipher_suites": [2570, 4865, 4866, 4867, 49195, 49199, 49196, 49200, 52393, 52392, 49171, 49172, 156, 157, 47, 53],
"curves": ["X25519", "P256", "P384"],
"versions": ["1.3", "1.2"],
"extensions": [2570, 0, 23, 65281, 10, 11, 35, 16, 5, 18, 13, 51, 45, 43, 27, 21]
},
"client_ip": "",
"user_agent": ""
}'
Änderungen werden sofort für neue Verbindungen wirksam. Setzen Sie mgmt_listen: "", um die API vollständig zu deaktivieren.
preset: "custom")Die integrierten Presets (chrome, firefox, safari, …) decken die häufigsten Fälle ab. Wenn Sie eine bestimmte Browserversion oder einen Fingerabdruck nachbilden müssen, der von diesen Presets abweicht, setzen Sie preset: "custom" und geben Sie einen custom_hello-Block an.
Wie JA3 / JA4 auf Konfigurationsfelder abgebildet werden
JA3 und JA4 sind Einweg-Hashes – Sie können einen Hash nicht zurück in eine Spezifikation auflösen. Ermitteln Sie die zugrunde liegenden Parameter des Zielbrowsers mit tls.peet.ws oder Wireshark und fügen Sie sie dann in
custom_helloein.
Chrome-131-Beispiel
tls:
preset: "custom"
custom_hello:
cipher_suites: # hex IDs; 0x0a0a = GREASE placeholder (randomised per connection)
- 0x0a0a
- 0x1301 # TLS_AES_128_GCM_SHA256
- 0x1302 # TLS_AES_256_GCM_SHA384
- 0x1303 # TLS_CHACHA20_POLY1305_SHA256
- 0xc02b # ECDHE-ECDSA-AES128-GCM-SHA256
- 0xc02f # ECDHE-RSA-AES128-GCM-SHA256
- 0xc02c # ECDHE-ECDSA-AES256-GCM-SHA384
- 0xc030 # ECDHE-RSA-AES256-GCM-SHA384
- 0xcca9 # ECDHE-ECDSA-CHACHA20-POLY1305
- 0xcca8 # ECDHE-RSA-CHACHA20-POLY1305
- 0xc013 # ECDHE-RSA-AES128-SHA
- 0xc014 # ECDHE-RSA-AES256-SHA
- 0x009c # RSA-AES128-GCM-SHA256
- 0x009d # RSA-AES256-GCM-SHA384
- 0x002f # RSA-AES128-SHA
- 0x0035 # RSA-AES256-SHA
curves: # X25519 | X25519Kyber768 | P256 | P384 | P521
- "X25519Kyber768"
- "X25519"
- "P256"
versions: # TLS versions to advertise
- "1.3"
- "1.2"
extensions: # extension type IDs in order (controls JA3 extensions component)
- 0x0a0a # GREASE
- 0 # server_name (SNI)
- 23 # extended_master_secret
- 65281 # renegotiation_info
- 10 # supported_groups
- 11 # ec_point_formats
- 35 # session_ticket
- 16 # ALPN
- 5 # status_request
- 18 # signed_certificate_timestamp
- 13 # signature_algorithms
- 51 # key_share
- 45 # psk_key_exchange_modes
- 43 # supported_versions
- 27 # compress_certificate
- 17513 # application_settings (ALPS)
- 0x0a0a # GREASE
- 21 # padding
Unterstützte Extension-Typ-IDs
Laufzeit-Updates:
preset: "custom"ist nicht aufconfig.yamlbeschränkt – es kann auch zur Laufzeit über die Management-API (POST /api/configmit einemcustom_hello-Objekt, siehe Management-API) oder über das TLS-Preset-Dropdown der Chrome-Erweiterung gewechselt werden, ohne den Proxy neu zu starten.
make run
# Kills any previous instance on port 8080, rebuilds, and starts.
Um Fingerabdruck-Profile zu wechseln, bearbeiten Sie config.yaml und führen Sie make run erneut aus.
# With CA trusted system-wide (after make trust-ca):
curl --proxy http://127.0.0.1:8080 https://tls.peet.ws/api/all
# Without system trust — pass CA explicitly:
curl --proxy http://127.0.0.1:8080 --cacert ca.crt https://tls.peet.ws/api/all
Das Verzeichnis chrome-extension/ enthält eine Manifest-V3-Erweiterung, die den Proxy über die Browser-Symbolleiste steuert.
Installation:
chrome://extensions in Chromechrome-extension/Bedienelemente:
User-Agent-Umfang: Die Erweiterung ändert nur den HTTP-
User-Agent-Header. Das JavaScript-navigator.userAgentwird von Chrome selbst gesteuert und ist nicht betroffen. Um beide gleichzeitig zu spoofen, starten Sie Chrome mit--user-agent="..."zusammen mit den Proxy-Einstellungen.
const { chromium } = require('playwright');
const browser = await chromium.launch();
const context = await browser.newContext({
proxy: { server: 'http://127.0.0.1:8080' },
});
// If CA is not in the system keychain, set before launching:
// NODE_EXTRA_CA_CERTS=./ca.crt node script.js
const page = await context.newPage();
await page.goto('https://tls.peet.ws/api/all');
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
context = browser.new_context(proxy={"server": "http://127.0.0.1:8080"})
page = context.new_page()
page.goto("https://tls.peet.ws/api/all")
Setzen Sie NODE_EXTRA_CA_CERTS (Node) oder REQUESTS_CA_BUNDLE (Python), wenn die CA nicht systemweit vertrauenswürdig ist.
tls.peet.ws gibt für jede eingehende Anfrage die vollständige Fingerabdruck-Aufschlüsselung zurück. Leiten Sie die Ausgabe für eine lesbare Ansicht durch jq oder Python:
curl -s --proxy http://127.0.0.1:8080 --cacert ca.crt \
https://tls.peet.ws/api/all | python3 -m json.tool
Wichtige Felder, die Sie prüfen sollten:
impersonate-proxy/
├── main.go # Entry point
├── config/config.go # YAML config struct and defaults
├── fp/dialer.go # uTLS dialer — TLS fingerprint presets
├── h2fp/conn.go # HTTP/2 framer — SETTINGS / WINDOW_UPDATE / pseudo-header control
├── mitm/ca.go # MITM CA: generate, cache, and serve leaf certs
├── proxy/proxy.go # Proxy server: CONNECT handling, protocol branch, runtime config
├── rewrite/headers.go # HTTP header rewriting (UA, order, add/remove, IP spoof)
├── mgmt/server.go # Management HTTP API (/api/config GET + POST)
├── chrome-extension/
│ ├── manifest.json # Manifest V3
│ ├── popup.html # Toolbar popup UI
│ ├── popup.css
│ ├── popup.js # Proxy toggle + management API client
│ └── icon.svg
├── config.yaml # Default configuration
└── Makefile
Binärdatei und erzeugte CA-Dateien entfernen:
make clean
Wenn Sie die CA zum macOS-Systemschlüsselbund hinzugefügt haben, entfernen Sie sie über die Schlüsselbundverwaltung (suchen Sie nach „impersonate-proxy CA") oder:
sudo security delete-certificate -c "impersonate-proxy CA" /Library/Keychains/System.keychain
Transfer-Encoding: chunked-Körpern werden derzeit nicht unterstützt.User-Agent-HTTP-Header neu, aber das JavaScript-navigator.userAgent wird vom Browser unabhängig gesetzt und ist nicht betroffen. Verwenden Sie das Startflag --user-agent von Chrome, um beide gleichzeitig zu überschreiben.Dieses Tool ist ausschließlich für autorisierte Sicherheitstests gedacht – beispielsweise zum Testen von WAF- und Bot-Erkennungskonfigurationen auf Systemen, die Ihnen gehören oder für die Sie eine ausdrückliche schriftliche Genehmigung zum Testen haben.
Die Verwendung dieses Tools gegen Systeme ohne Genehmigung kann geltende Gesetze verletzen (z. B. den Computer Fraud and Abuse Act, das japanische Gesetz gegen unbefugten Computerzugriff oder entsprechende Gesetze in Ihrem Land) sowie die Nutzungsbedingungen des Ziels.
Die Autoren übernehmen keinerlei Haftung für Missbrauch.
custom_hello| HTTP/1.1 | Header-Reihenfolge, User-Agent, beliebige Header hinzufügen/entfernen, IP-Spoofing (X-Forwarded-For / True-Client-IP) |
| HTTP/2 | SETTINGS-Werte und -Reihenfolge, WINDOW_UPDATE, Pseudo-Header-Reihenfolge (HTTP/2-Fingerabdruck) |
Aktive Einstellungen als JSON zurückgeben, einschließlich des aktuellen custom_hello |
/api/config | POST | TLS-Preset (einschließlich eines vollständig benutzerdefinierten custom_hello), Client-IP und User-Agent aktualisieren |
| Browser | TLS-Preset | HTTP/2 SETTINGS | WINDOW_UPDATE |
|---|
| Chrome | chrome | 1:65536,2:0,4:6291456,6:262144 | 15663105 |
| Firefox | firefox | 1:65536,4:131072,5:16384 | 12517377 |
| Safari | safari | 1:4096,3:100,4:2097152,6:16384 | 10485760 |
| Fingerabdruck-Komponente | Konfigurationsfeld | Hinweise |
|---|
| TLS-Versionsbereich | versions | Min/Max werden automatisch abgeleitet |
| Cipher-Suite-Liste + Reihenfolge | cipher_suites | 0x0a0a als GREASE-Platzhalter verwenden; uTLS randomisiert ihn pro Verbindung |
| Extension-Typ-IDs + Reihenfolge | extensions | Die Reihenfolge steuert direkt die JA3-Extensions-Komponente; Werte, die dem GREASE-Muster (0xXAXA) entsprechen, werden pro Verbindung randomisiert |
| Unterstützte Gruppen (Kurven) | curves | Steuert auch, welche Key Shares gesendet werden |
| ID | Name | Hinweise |
|---|
0xXAXA (beliebiges GREASE-Muster) | GREASE | Pro Verbindung randomisiert |
0 | server_name (SNI) | |
5 | status_request | OCSP-Stapling |
10 | supported_groups | Verwendet die curves-Liste |
11 | ec_point_formats | Fest: uncompressed (0) |
13 | signature_algorithms | Chrome-ähnliche Standardwerte |
16 | ALPN | Wirbt mit h2, http/1.1 |
18 | signed_certificate_timestamp | |
21 | padding | BoringSSL-ähnliches Padding |
23 | extended_master_secret | |
27 | compress_certificate | |
28 | record_size_limit | Fest: 0x4001 |
35 | session_ticket | |
43 | supported_versions | Verwendet die versions-Liste |
45 | psk_key_exchange_modes | PSK mit DHE |
50 | signature_algorithms_cert | Chrome-ähnliche Standardwerte |
51 | key_share | Key Shares für X25519 und P256 (aus curves) |
17513 | application_settings (ALPS) | Wirbt mit h2 |
65281 | renegotiation_info | |
| andere | GenericExtension | Wird mit leerer Nutzlast gesendet |
| Bedienelement | Funktion |
|---|
| Proxy-Umschalter | Aktiviert / deaktiviert die Proxy-Einstellung von Chrome (leitet Datenverkehr durch :8080) |
| TLS-Preset | Wechselt das uTLS-Fingerabdruck-Preset (chrome / firefox / safari / edge / ios / random / golang / custom) |
| Cipher Suites / Curves / TLS-Versionen / Extensions | Werden angezeigt, wenn Custom (JA3/JA4) ausgewählt ist – dieselben Felder wie custom_hello in config.yaml, sodass Sie einen beliebigen JA3/JA4-Fingerabdruck einstellen können, ohne YAML zu bearbeiten oder den Proxy neu zu starten |
| Client-IP | Setzt X-Forwarded-For und True-Client-IP bei jeder Anfrage |
| User-Agent | Überschreibt den HTTP-User-Agent-Header |
| Apply-Schaltfläche | Sendet die neuen Einstellungen per POST an die Management-API; wirkt sofort |
| API-Feld | Adresse der Management-API (Standard http://127.0.0.1:8081) |
| Feld | Beschreibung |
|---|
tls.ja3_hash | JA3-Fingerabdruck-Hash |
tls.ja4 | JA4-Fingerabdruck-String |
http2.akamai_fingerprint | HTTP/2-Fingerabdruck-String (SETTINGS + WINDOW_UPDATE + Pseudo-Header-Reihenfolge) – der Feldname wird von der tls.peet.ws-API definiert |
http1.headers | Header-Namen in der vom Server empfangenen Reihenfolge |
user_agent | User-Agent, wie vom Server gesehen |
ip | Quell-IP, wie vom Server gesehen – überprüfen Sie hier das Spoofing von X-Forwarded-For / True-Client-IP |
| Ziel | Beschreibung |
|---|
make build | Binärdatei kompilieren |
make run | Bauen, eine vorhandene Instanz beenden und starten |
make trust-ca | ca.crt zum macOS-Systemschlüsselbund hinzufügen (erfordert sudo) |
make clean | Binärdatei, ca.crt und ca.key entfernen |