セキュリティ
Show HN: TLSフィンガープリントを制御できるローカルMitMプロキシ
Show HN: A local MitM proxy to control TLS fingerprints (github.com)
要約
impersonate-proxyは、YAML設定ファイルからTLSフィンガープリント(JA3/JA4)、HTTP/2フィンガープリント、HTTPヘッダー順序、User-Agent、ソースIPヘッダーを制御できるローカルのMITMプロキシです。Chrome拡張機能も含まれており、プロキシを再起動せずにブラウザツールバーから直接プロキシの切り替えやフィンガープリントプロファイルの変更が可能です。WAFボット検出システムの正規のセキュリティテストを目的としています。
全文翻訳
impersonate-proxy
TLSフィンガープリントを制御できるローカルMITMプロキシ
単一のYAML設定ファイルから、TLSフィンガープリント(JA3/JA4)、HTTP/2フィンガープリント、HTTPヘッダー順序、User-Agent、ソースIPヘッダーを制御できるローカルMITMプロキシです。Chrome拡張機能も含まれており、プロキシを再起動せずにブラウザツールバーから直接プロキシの切り替えやフィンガープリントプロファイルの変更が可能です。WAFボット検出システムの正規のセキュリティテストを目的としています。
curl、ブラウザ、またはPlaywrightをプロキシ経由でルーティングして、さまざまなフィンガープリントの組み合わせがどのように分類されるかを観察します。
仕組み
curl / browser / Playwright
│ HTTP CONNECT (プロキシへ)
▼
┌─────────────────────────────────────────┐
│ impersonate-proxy │
│ │
│ MITM TLS ◄──────────────► uTLS │
│ (当社のCA証明書) (カスタムJA3/4) │
│ │
│ ヘッダーリライター(UA、順序、追加/削除)│
│ HTTP/2フレーマー(SETTINGS、WINDOW_UPDATE
│ 疑似ヘッダー順序) │
└─────────────────────────────────────────┘
│ カスタムTLSクライアントハロー + HTTP/2
▼
ターゲットサーバー / WAFレイヤー
制御できるもの
TLS暗号スイート、拡張機能、その順序(JA3 / JA4) — uTLSプリセットまたは完全にカスタムなcustom_hello仕様を通じて
HTTP/1.1 ヘッダー順序、User-Agent、任意のヘッダーの追加/削除、IPスプーフィング(X-Forwarded-For / True-Client-IP)
HTTP/2 SETTINGS 値と順序、WINDOW_UPDATE、疑似ヘッダー順序(HTTP/2フィンガープリント)
前提条件
macOSまたはLinux(amd64 / arm64)
Go 1.22+
macOS
brew install go
Linux
ディストリビューションパッケージのGoはしばしば古いです。公式バイナリを直接インストールしてください:
# ダウンロードして展開します(https://go.dev/dl/ から最新バージョンに1.22.5を置き換えてください)
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
# PATHに追加します(永続化するには、この行を~/.bashrcまたは~/.zshrcに追加してください)
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に置き換えてください。
セットアップ
1. クローンしてビルドする
git clone https://github.com/ytkoka/impersonate-proxy.git
cd impersonate-proxy
make build
2. MITM CA証明書を生成する
CAは初回実行時に自動生成されます。ca.crtとca.keyを作成するためにプロキシを一度実行します:
make run
# 2026/04/22 12:00:00 生成されたCA証明書 → ca.crt
# 2026/04/22 12:00:00 127.0.0.1:8080 でリッスン中 preset=chrome
Ctrl-C で停止します。
3. CA証明書を信頼する
クライアントは、プロキシ生成のリーフ証明書を拒否しないように、当社のMITM CAを信頼する必要があります。
macOS システムキーチェーン(すべてのアプリに影響):
make trust-ca
# 実行内容: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:
Preferences → Privacy & Security → View Certificates → Authorities → Import ca.crt
設定
プロキシを開始する前に config.yaml を編集します。すべてのフィールドにはデフォルト値があります — オーバーライドしたいものだけを指定する必要があります。
listen: "127.0.0.1:8080"
mgmt_listen: "127.0.0.1:8081" # Chrome拡張機能が使用する管理API(無効にする場合は空にする)
ca_cert: "ca.crt"
ca_key: "ca.key"
tls:
# TLSフィンガープリントプリセット(JA3 / JA4を制御)
# オプション:chrome | firefox | safari | edge | ios | random | golang
preset: "chrome"
http:
# User-Agentをオーバーライドします(クライアントの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"
# ソースIPをスプーフィングします:X-Forwarded-ForとTrue-Client-IPの両方をこの値に設定します。
# クライアントが既に設定した値を上書きします(無効にする場合は空のままにします)
# client_ip: "1.2.3.4"
# この順序でヘッダーを発行します。リストにないヘッダーは後に追加されます。
header_order:
- "Host"
- "User-Agent"
- "Accept"
- "Accept-Language"
- "Accept-Encoding"
- "Connection"
# フォワーディング前にヘッダーを削除します
add_headers:
Accept-Language: "ja,en-US;q=0.9,en;q=0.8"
# ヘッダーを削除します
remove_headers: []
http2:
enabled: true
# SETTINGSフレームエントリ — IDと順序の両方がHTTP/2フィンガープリントに影響します。
# RFC 7540 §11.3 ID:
# 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のデフォルトが表示されています
- { id: 2, val: 0 }
- { id: 4, val: 6291456 }
- { id: 6, val: 262144 }
# コネクションレベルのWINDOW_UPDATEインクリメント
window_update: 15663105
# HEADERSフレーム内の疑似ヘッダーの順序
pseudo_header_order:
- method
- authority
- scheme
- path
管理API
プロキシが起動すると、mgmt_listen(デフォルト127.0.0.1:8081)で軽量HTTP APIも公開します。Chrome拡張機能はこれを使用して、プロキシを再起動せずに実行時に設定を読み取り、更新します。curlで直接呼び出すこともできます:
エンドポイント
メソッド
説明
/api/config
GET
現在の設定をJSONとして返します。現在のcustom_helloも含まれます。
/api/config
POST
TLSプリセット(完全にカスタムなcustom_helloを含む)、クライアントIP、およびUser-Agentを更新します。
# 現在の設定を読み取る
curl http://127.0.0.1:8081/api/config
# Firefoxフィンガープリントに切り替え、スプーフィングされた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":""}'
# 実行時に任意のJA3/JA4フィンガープリントに切り替える — config.yamlのcustom_helloブロックと同じフィールドをJSONで送信します(「カスタムTLSフィンガープリント」を参照)
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": "" }'
変更は新しい接続に対して即座に有効になります。
APIを完全に無効にするには、mgmt_listen: "" を設定します。
ブラウザフィンガープリントリファレンス
ブラウザ
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フィンガープリント(プリセット:「custom」)
組み込みのプリセット(chrome、firefox、safariなど)は、最も一般的なケースをカバーしています。特定のブラウザバージョンやプリセットとは異なるフィンガープリントに一致させる必要がある場合は、preset: "custom" を設定し、custom_helloブロックを提供します。
JA3 / JA4が設定フィールドにマッピングされる方法
フィンガープリントコンポーネント
設定フィールド
注記
TLSバージョン範囲
versions
最小/最大は自動的に導出されます
暗号スイートリスト + 順序
cipher_suites
GREASEプレースホルダーとして0x0a0aを使用します。uTLSは接続ごとにランダム化します。
拡張機能タイプID + 順序
extensions
順序はJA3拡張機能コンポーネントを直接制御します。GREASEパターン(0xXAXA)に一致する値は、接続ごとにランダム化されます。
サポートされているグループ(曲線)
curves
キー共有が送信されるものを制御します。
JA3とJA4は一方向ハッシュです — ハッシュを仕様に戻すことはできません。tls.peet.wsまたはWiresharkを使用してターゲットブラウザの基になるパラメータを見つけ、custom_helloに貼り付けます。
Chrome 131の例
tls:
preset: "custom"
custom_hello:
cipher_suites:
# 16進数ID;0x0a0a = GREASEプレースホルダー(接続ごとにランダム化)
- 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
curves:
- "X25519"
- "P256"
- "P384"
versions:
- "1.3"
- "1.2"
extensions:
- 0x0a0a # GREASE
- 0 # Server Name
- 23 # Session Ticket TLS
- 65281 # Extended Master Secret
- 10 # Certificate Status Request
- 11 # Supported Groups
- 35 # Session Ticket
- 16 # Application-Layer Protocol Negotiation
- 5 # Status Request
- 18 # User Transfer
- 13 # Signature Algorithms
- 51 # Key Share
- 45 # Certificate Authorities
- 43 # Supported Versions
- 27 # New Session Ticket Message
- 21 # ALPN