
Um proxy MITM local que permite controlar fingerprints de TLS (JA3/JA4), fingerprints de HTTP/2, a ordem dos cabeçalhos HTTP e o User-Agent — tudo a partir de um único arquivo de configuração YAML.
Um proxy MITM local que permite controlar impressões digitais TLS (JA3/JA4), impressões digitais HTTP/2, ordem dos cabeçalhos HTTP, User-Agent e cabeçalhos de IP de origem — tudo a partir de um único arquivo de configuração YAML.
Uma extensão do Chrome é incluída para ativar/desativar o proxy e alternar perfis de impressão digital diretamente da barra de ferramentas do navegador, sem reiniciar o proxy.
Destinada a testes de segurança autorizados de sistemas de detecção de bots em WAF. Roteie curl, navegadores ou Playwright pelo proxy para observar como diferentes combinações de impressões digitais são classificadas.
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
| Camada | O que você pode controlar |
|---|---|
| TLS | Suites de cifras, extensões, sua ordem (JA3 / JA4) via presets do uTLS ou uma especificação totalmente personalizada |
brew install go
O Go empacotado pela distribuição geralmente está desatualizado. Instale o binário oficial diretamente:
# 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
Verifique:
go version
# go version go1.22.5 linux/amd64
ARM64 (Raspberry Pi, AWS Graviton, etc.): substitua
linux-amd64porlinux-arm64na URL de download.
git clone https://github.com/ytkoka/impersonate-proxy.git
cd impersonate-proxy
make build
A CA é gerada automaticamente na primeira execução. Inicie o proxy uma vez para criar ca.crt e 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
Pare-o com Ctrl-C.
Os clientes precisam confiar na sua CA MITM para não rejeitarem os certificados folha gerados pelo proxy.
Chaveiro do sistema macOS (afeta todos os aplicativos):
make trust-ca # runs: sudo security add-trusted-cert ...
Confiança do sistema Linux (afeta todos os aplicativos; requer o pacote 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
Somente curl (sem alteração no sistema):
curl --cacert ca.crt ...
Playwright / Node.js:
export NODE_EXTRA_CA_CERTS="$(pwd)/ca.crt"
Firefox: Preferências → Privacidade e Segurança → Ver Certificados → Autoridades → Importar ca.crt
Edite config.yaml antes de iniciar o proxy. Todos os campos têm valores padrão — você só precisa especificar o que deseja sobrescrever.
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]
Ao iniciar, o proxy também expõe uma API HTTP leve em mgmt_listen (padrão 127.0.0.1:8081). A extensão do Chrome a utiliza para ler e atualizar configurações em tempo de execução sem reiniciar o proxy. Você também pode chamá-la diretamente com curl:
| Endpoint | Método | Descrição |
|---|---|---|
/api/config |
# 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": ""
}'
As alterações entram em vigor imediatamente para novas conexões. Defina mgmt_listen: "" para desativar completamente a API.
preset: "custom")Os presets integrados (chrome, firefox, safari, …) cobrem os casos mais comuns. Quando você precisar corresponder a uma versão específica do navegador ou a uma impressão digital diferente desses presets, defina preset: "custom" e forneça um bloco custom_hello.
Como JA3 / JA4 mapeiam para os campos de configuração
JA3 e JA4 são hashes unidirecionais — você não pode reverter um hash para uma especificação. Encontre os parâmetros subjacentes do navegador alvo com tls.peet.ws ou Wireshark e cole-os em
custom_hello.
Exemplo do 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
IDs de tipo de extensão suportados
Atualizações em tempo de execução:
preset: "custom"não se limita aoconfig.yaml— também é possível alternar para ele em tempo de execução via API de gerenciamento (POST /api/configcom um objetocustom_hello, veja API de gerenciamento) ou pelo menu suspenso TLS Preset da extensão do Chrome, sem reiniciar o proxy.
make run
# Kills any previous instance on port 8080, rebuilds, and starts.
Para alternar perfis de impressão digital, edite config.yaml e execute make run novamente.
# 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
O diretório chrome-extension/ contém uma extensão Manifest V3 que controla o proxy a partir da barra de ferramentas do navegador.
Instalação:
chrome://extensions no Chromechrome-extension/Controles:
Escopo do User-Agent: A extensão altera apenas o cabeçalho HTTP
User-Agent. Onavigator.userAgentdo JavaScript é controlado pelo próprio Chrome e não é afetado. Para falsificar ambos simultaneamente, inicie o Chrome com--user-agent="..."junto com as configurações do proxy.
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")
Defina NODE_EXTRA_CA_CERTS (Node) ou REQUESTS_CA_BUNDLE (Python) se a CA não for confiável em todo o sistema.
tls.peet.ws retorna o detalhamento completo da impressão digital para qualquer requisição que recebe. Envie a saída por jq ou Python para uma visualização legível:
curl -s --proxy http://127.0.0.1:8080 --cacert ca.crt \
https://tls.peet.ws/api/all | python3 -m json.tool
Campos principais a verificar:
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
Remova o binário e os arquivos de CA gerados:
make clean
Se você adicionou a CA ao chaveiro do sistema macOS, remova-a pelo Acesso às Chaves (procure por "impersonate-proxy CA") ou:
sudo security delete-certificate -c "impersonate-proxy CA" /Library/Keychains/System.keychain
Transfer-Encoding: chunked não são suportadas atualmente.User-Agent, mas o navigator.userAgent do JavaScript é definido pelo navegador de forma independente e não é afetado. Use a flag de inicialização --user-agent do Chrome para sobrescrever ambos simultaneamente.Esta ferramenta é destinada somente a testes de segurança autorizados — por exemplo, testar configurações de WAF e detecção de bots em sistemas que você possui ou para os quais tem permissão explícita por escrito para testar.
Usar esta ferramenta contra sistemas sem autorização pode violar leis aplicáveis (como o Computer Fraud and Abuse Act, a Lei Japonesa de Acesso Não Autorizado a Computadores ou legislação equivalente em sua jurisdição) e os termos de serviço do alvo.
Os autores não aceitam nenhuma responsabilidade por uso indevido.
custom_hello| HTTP/1.1 | Ordem dos cabeçalhos, User-Agent, adicionar/remover qualquer cabeçalho, falsificação de IP (X-Forwarded-For / True-Client-IP) |
| HTTP/2 | Valores e ordem de SETTINGS, WINDOW_UPDATE, ordem de pseudo-cabeçalhos (impressão digital HTTP/2) |
GET |
Retorna as configurações ativas como JSON, incluindo o custom_hello atual |
/api/config | POST | Atualiza o preset TLS (incluindo um custom_hello totalmente personalizado), o IP do cliente e o User-Agent |
| Navegador | Preset 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 |
| Componente da impressão digital | Campo de configuração | Observações |
|---|
| Faixa de versões TLS | versions | Mín./máx. são derivados automaticamente |
| Lista e ordem de suites de cifras | cipher_suites | Use 0x0a0a como espaço reservado GREASE; o uTLS o randomiza por conexão |
| IDs e ordem de extensões | extensions | A ordem controla diretamente o componente de extensões do JA3; valores que correspondem ao padrão GREASE (0xXAXA) são randomizados por conexão |
| Grupos suportados (curvas) | curves | Também controla quais key shares são enviados |
| ID | Nome | Observações |
|---|
0xXAXA (qualquer padrão GREASE) | GREASE | Randomizado por conexão |
0 | server_name (SNI) | |
5 | status_request | OCSP stapling |
10 | supported_groups | Usa a lista curves |
11 | ec_point_formats | Fixo: uncompressed (0) |
13 | signature_algorithms | Padrões semelhantes aos do Chrome |
16 | ALPN | Anuncia h2, http/1.1 |
18 | signed_certificate_timestamp | |
21 | padding | Padding no estilo BoringSSL |
23 | extended_master_secret | |
27 | compress_certificate | |
28 | record_size_limit | Fixo: 0x4001 |
35 | session_ticket | |
43 | supported_versions | Usa a lista versions |
45 | psk_key_exchange_modes | PSK com DHE |
50 | signature_algorithms_cert | Padrões semelhantes aos do Chrome |
51 | key_share | Key shares para X25519 e P256 (de curves) |
17513 | application_settings (ALPS) | Anuncia h2 |
65281 | renegotiation_info | |
| outro | GenericExtension | Enviado com payload vazio |
| Controle | O que faz |
|---|
| Alternância do proxy | Ativa / desativa a configuração de proxy do Chrome (roteia o tráfego por :8080) |
| TLS Preset | Alterna o preset de impressão digital do uTLS (chrome / firefox / safari / edge / ios / random / golang / custom) |
| Cipher Suites / Curves / TLS Versions / Extensions | Exibidos quando Custom (JA3/JA4) está selecionado — os mesmos campos de custom_hello em config.yaml, permitindo ajustar uma impressão digital JA3/JA4 arbitrária sem editar YAML ou reiniciar o proxy |
| Client IP | Define X-Forwarded-For e True-Client-IP em cada requisição |
| User-Agent | Substitui o cabeçalho HTTP User-Agent |
| Botão Aplicar | Envia as novas configurações para a API de gerenciamento via POST; entra em vigor imediatamente |
| Campo API | Endereço da API de gerenciamento (padrão http://127.0.0.1:8081) |
| Campo | Descrição |
|---|
tls.ja3_hash | Hash da impressão digital JA3 |
tls.ja4 | String da impressão digital JA4 |
http2.akamai_fingerprint | String da impressão digital HTTP/2 (SETTINGS + WINDOW_UPDATE + ordem de pseudo-cabeçalhos) — o nome do campo é definido pela API do tls.peet.ws |
http1.headers | Nomes dos cabeçalhos na ordem recebida pelo servidor |
user_agent | User-Agent como visto pelo servidor |
ip | IP de origem como visto pelo servidor — verifique aqui a falsificação de X-Forwarded-For / True-Client-IP |
| Alvo | Descrição |
|---|
make build | Compila o binário |
make run | Compila, encerra qualquer instância existente e inicia |
make trust-ca | Adiciona ca.crt ao chaveiro do sistema macOS (requer sudo) |
make clean | Remove o binário, ca.crt e ca.key |