一个本地 MITM 代理,让你能够通过单个 YAML 配置文件控制 TLS 指纹(JA3/JA4)、HTTP/2 指纹、HTTP 标头顺序、User-Agent 以及来源 IP 标头。
附带一个 Chrome 扩展,可直接从浏览器工具栏切换代理开关和指纹配置,无需重启代理。
适用于对 WAF 机器人检测系统进行授权安全测试。通过代理路由 curl、浏览器或 Playwright 的流量,观察不同的指纹组合会被如何分类。
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
| 层 | 可控制的内容 |
|---|---|
| TLS | 通过 uTLS 预设或完全自定义的 custom_hello 规范,控制密码套件、扩展及其顺序(JA3 / JA4) |
| HTTP/1.1 | 标头顺序、User-Agent、添加/删除任意标头、IP 伪装(X-Forwarded-For / True-Client-IP) |
| HTTP/2 | SETTINGS 值及顺序、WINDOW_UPDATE、伪标头顺序(HTTP/2 指纹) |
brew install go
发行版自带的 Go 版本通常较旧。请直接安装官方二进制文件:
# 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
验证:
go version
# go version go1.22.5 linux/amd64
ARM64(Raspberry Pi、AWS Graviton 等): 将下载 URL 中的
linux-amd64替换为linux-arm64。
git clone https://github.com/ytkoka/impersonate-proxy.git
cd impersonate-proxy
make build
CA 会在首次运行时自动生成。先启动一次代理以生成 ca.crt 和 ca.key:
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
按 Ctrl-C 停止。
客户端需要信任你的 MITM CA,否则它们会拒绝代理生成的叶证书。
macOS 系统钥匙串(影响所有应用):
make trust-ca # runs: sudo security add-trusted-cert ...
Linux 系统信任(影响所有应用;需要 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
仅 curl(不做系统级更改):
curl --cacert ca.crt ...
Playwright / Node.js:
export NODE_EXTRA_CA_CERTS="$(pwd)/ca.crt"
Firefox:设置 → 隐私与安全 → 查看证书 → 证书机构 → 导入 ca.crt
在启动代理前编辑 config.yaml。所有字段都有默认值——你只需指定要覆盖的字段。
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]
代理启动时还会在 mgmt_listen(默认 127.0.0.1:8081)上暴露一个轻量级 HTTP API。Chrome 扩展通过此 API 在运行时读取和更新设置,无需重启代理。你也可以直接用 curl 调用它:
| 端点 | 方法 | 说明 |
|---|---|---|
/api/config | GET | 以 JSON 形式返回当前生效的设置,包括当前的 custom_hello |
# 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": ""
}'
更改对新连接立即生效。将 mgmt_listen: "" 设置为空即可完全禁用该 API。
preset: "custom")内置预设(chrome、firefox、safari 等)覆盖了最常见的情况。当需要匹配特定的浏览器版本或与这些预设不同的指纹时,请设置 preset: "custom" 并提供 custom_hello 块。
JA3 / JA4 如何映射到配置字段
JA3 和 JA4 是单向哈希——你无法从哈希反推回规范。请使用 tls.peet.ws 或 Wireshark 获取目标浏览器的底层参数,然后将其粘贴到
custom_hello中。
Chrome 131 示例
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
支持的扩展类型 ID
运行时更新:
preset: "custom"并不仅限于config.yaml——你也可以在运行时通过管理 API(使用custom_hello对象执行POST /api/config,参见管理 API)或通过 Chrome 扩展的 TLS 预设下拉菜单切换到该值,无需重启代理。
make run
# Kills any previous instance on port 8080, rebuilds, and starts.
要切换指纹配置,请编辑 config.yaml 并重新运行 make run。
# 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
chrome-extension/ 目录包含一个 Manifest V3 扩展,可从浏览器工具栏控制代理。
安装:
chrome://extensionschrome-extension/ 文件夹控件:
User-Agent 作用范围: 该扩展仅更改 HTTP
User-Agent标头。JavaScript 的navigator.userAgent由 Chrome 本身控制,不受影响。要同时伪装两者,请在使用代理设置的同时,以--user-agent="..."参数启动 Chrome。
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")
如果 CA 未在系统范围内受信任,请设置 NODE_EXTRA_CA_CERTS(Node)或 REQUESTS_CA_BUNDLE(Python)。
tls.peet.ws 会为其收到的任何请求返回完整的指纹明细。将输出通过 jq 或 Python 管道处理,可获得更易读的视图:
curl -s --proxy http://127.0.0.1:8080 --cacert ca.crt \
https://tls.peet.ws/api/all | python3 -m json.tool
需要检查的关键字段:
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
删除二进制文件和生成的 CA 文件:
make clean
如果你已将 CA 添加到 macOS 系统钥匙串,可通过钥匙串访问(Keychain Access)删除它(搜索“impersonate-proxy CA”),或执行:
sudo security delete-certificate -c "impersonate-proxy CA" /Library/Keychains/System.keychain
Transfer-Encoding: chunked 请求体的请求。User-Agent HTTP 标头,但 JavaScript 的 navigator.userAgent 由浏览器独立设置,不受影响。如需同时伪装两者,请使用 Chrome 的 --user-agent 启动参数。本工具仅用于授权安全测试——例如,在你拥有或已获明确书面许可测试的系统上,测试 WAF 和机器人检测配置。
未经授权对系统使用本工具,可能违反适用法律(如美国《计算机欺诈与滥用法》、日本《禁止未经授权访问计算机法》或你所在司法辖区的同等法律)以及目标的服务条款。
作者对滥用行为不承担任何责任。
/api/configPOST |
更新 TLS 预设(包括完全自定义的 custom_hello)、客户端 IP 和 User-Agent |
| 浏览器 | TLS 预设 | 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 |
| 指纹组件 | 配置字段 | 说明 |
|---|
| TLS 版本范围 | versions | 最小/最大版本会自动推导 |
| 密码套件列表及顺序 | cipher_suites | 使用 0x0a0a 作为 GREASE 占位符;uTLS 会在每次连接时将其随机化 |
| 扩展类型 ID 及顺序 | extensions | 顺序直接控制 JA3 的扩展组件;符合 GREASE 模式(0xXAXA)的值会在每次连接时随机化 |
| 支持组(曲线) | curves | 同时控制发送哪些密钥共享 |
| ID | 名称 | 说明 |
|---|
0xXAXA(任意 GREASE 模式) | GREASE | 每次连接时随机化 |
0 | server_name (SNI) | |
5 | status_request | OCSP 装订 |
10 | supported_groups | 使用 curves 列表 |
11 | ec_point_formats | 固定:未压缩(0) |
13 | signature_algorithms | Chrome 风格默认值 |
16 | ALPN | 通告 h2、http/1.1 |
18 | signed_certificate_timestamp | |
21 | padding | BoringSSL 风格填充 |
23 | extended_master_secret | |
27 | compress_certificate | |
28 | record_size_limit | 固定:0x4001 |
35 | session_ticket | |
43 | supported_versions | 使用 versions 列表 |
45 | psk_key_exchange_modes | PSK 与 DHE |
50 | signature_algorithms_cert | Chrome 风格默认值 |
51 | key_share | X25519 和 P256 的密钥共享(来自 curves) |
17513 | application_settings (ALPS) | 通告 h2 |
65281 | renegotiation_info | |
| 其他 | GenericExtension | 以空负载发送 |
| 控件 | 功能 |
|---|
| 代理开关 | 启用 / 禁用 Chrome 的代理设置(将流量路由到 :8080) |
| TLS 预设 | 切换 uTLS 指纹预设(chrome / firefox / safari / edge / ios / random / golang / custom) |
| 密码套件 / 曲线 / TLS 版本 / 扩展 | 选择**自定义(JA3/JA4)**时显示——与 config.yaml 中 custom_hello 的字段相同,无需编辑 YAML 或重启代理,即可调出任意 JA3/JA4 指纹 |
| 客户端 IP | 在每个请求上设置 X-Forwarded-For 和 True-Client-IP |
| User-Agent | 覆盖 HTTP User-Agent 标头 |
| 应用按钮 | 将新设置 POST 到管理 API;立即生效 |
| API 地址字段 | 管理 API 的地址(默认 http://127.0.0.1:8081) |
| 字段 | 说明 |
|---|
tls.ja3_hash | JA3 指纹哈希 |
tls.ja4 | JA4 指纹字符串 |
http2.akamai_fingerprint | HTTP/2 指纹字符串(SETTINGS + WINDOW_UPDATE + 伪标头顺序)——字段名由 tls.peet.ws API 定义 |
http1.headers | 服务器接收到的标头名称顺序 |
user_agent | 服务器看到的 User-Agent |
ip | 服务器看到的来源 IP——在此处验证 X-Forwarded-For / True-Client-IP 伪装 |
| 目标 | 说明 |
|---|
make build | 编译二进制文件 |
make run | 构建、终止任何已有实例并启动 |
make trust-ca | 将 ca.crt 添加到 macOS 系统钥匙串(需要 sudo) |
make clean | 删除二进制文件、ca.crt 和 ca.key |