Você tem um script escrito em Python. Ele sai por um proxy, o endereço IP muda a cada requisição e no cabeçalho User-Agent você colocou uma linha atual do Chrome. Mesmo assim o site responde 403 logo na primeira requisição. Abra o mesmo endereço pelo mesmo IP em um navegador de verdade e a página carrega. A diferença está em um pacote que viaja antes de qualquer cabeçalho HTTP: a mensagem ClientHello, que abre a conexão criptografada. Olhando como essa mensagem é montada, um site percebe se está falando com o Chrome, com o Python ou com o curl sem ler um único cabeçalho.
Neste texto vemos o handshake TLS, os campos dentro do ClientHello, como a string JA3 é calculada a partir desses campos e o que o JA4 faz de diferente. Depois passamos à pergunta que mais chega até nós: um proxy muda o fingerprint TLS? No final há um exemplo em Python já testado que mostra localmente a string JA3 do seu próprio cliente.
O que é o handshake TLS?
TLS é o protocolo que criptografa o tráfego entre o navegador e o site; o https:// na barra de endereços mostra que você está usando ele. Antes de a criptografia começar, os dois lados precisam combinar qual versão, qual suíte de cifra e qual chave usar. Essa negociação curta se chama handshake. A versão atual, o TLS 1.3, está definida na RFC 8446, e o handshake corre mais ou menos assim:
- O cliente se conecta ao servidor por TCP e envia uma mensagem
ClientHello. Nela vão as suítes de cifra e as extensões que ele suporta, além da sua parcela de chave. - O servidor escolhe da lista e responde com
ServerHello. Daí em diante os dois lados conseguem derivar a chave compartilhada. - O servidor envia o certificado e uma mensagem
Finishedque prova a integridade do handshake, ambos criptografados. - O cliente verifica o certificado e manda a sua própria mensagem
Finished. - Só então a primeira requisição HTTP (
GET /, cabeçalhos,User-Agent) viaja, dentro do canal criptografado.
Para o fingerprint, o que importa é o passo um. O ClientHello é enviado antes de existir qualquer chave compartilhada, então vai sem criptografia; o servidor, o CDN à frente dele e cada equipamento de rede no caminho conseguem lê-lo como está, antes de qualquer cabeçalho, cookie ou linha de JavaScript.
Quais campos a mensagem ClientHello contém?
O ClientHello é uma lista em que o cliente diz «isto é o que eu sei falar». Estes são os campos usados no fingerprint:
| Campo | O que carrega? | Por que diferencia? |
|---|---|---|
legacy_version | O campo de versão antigo. Por compatibilidade, clientes de TLS 1.3 ainda escrevem aqui o valor do TLS 1.2 (771) | Sozinho diz pouco; a versão real está em uma extensão |
cipher_suites | Suítes de cifra suportadas, em ordem de preferência | Tanto a lista quanto a ordem variam de biblioteca para biblioteca |
extensions | Os números de tipo das extensões: server_name (0), supported_groups (10), signature_algorithms (13), ALPN (16), supported_versions (43), key_share (51) e outras | Quais extensões existem, e em que ordem, é próprio de cada software |
supported_groups | Curvas e grupos utilizáveis na troca de chaves (29 = x25519, 23 = secp256r1) | Grupos novos chegam primeiro aos navegadores |
ec_point_formats | Formatos de ponto de curva elíptica | Algumas bibliotecas enviam três valores, outras só um |
signature_algorithms | Algoritmos de assinatura aceitos, em ordem | O JA3 não usa, o JA4 usa |
| ALPN | O protocolo de aplicação que o cliente quer falar (h2, http/1.1) | Um navegador pede h2; clientes simples quase nunca pedem |
Quem preenche essas listas não é a sua aplicação, e sim a biblioteca TLS por baixo dela. O Chrome usa BoringSSL e o Firefox usa NSS. O módulo ssl do Python e o Node.js são construídos sobre OpenSSL. O curl que vem com o Windows usa Schannel, a pilha TLS do próprio sistema operacional. Cada biblioteca tem uma lista de cifras padrão, um conjunto de extensões e uma ordenação diferentes; é assim que a identidade do cliente vaza para o primeiro pacote do handshake.
O que é um fingerprint TLS?
Um fingerprint TLS são essas listas do ClientHello reduzidas a uma string curta e comparável. Três propriedades o separam de outros sinais:
- Ele é passivo. O site não faz o cliente executar nada; apenas lê o primeiro pacote que chega. Desligar o JavaScript ou apagar os cookies não muda o resultado.
- Ele independe dos cabeçalhos. O
User-Agenté uma linha de texto e muda com uma linha de código em qualquer biblioteca HTTP. OClientHellovem do comportamento compilado da biblioteca. - Ele identifica o software, não a pessoa. Todo mundo que roda a mesma versão do Chrome no mesmo sistema operacional produz o mesmo valor. A camada de JavaScript (canvas, fontes, WebGL), que tenta separar dispositivos um a um, está em O que é fingerprint do navegador?.
O método não foi inventado para detectar bots. O primeiro uso foi segurança de rede: malware criptografa o tráfego, mas a biblioteca TLS e as configurações costumam ser fixas. Um time de segurança que não enxerga o conteúdo ainda reconhece a mesma família de software pelo desenho do ClientHello.
O que é o JA3 e como ele é calculado?
O JA3 é o primeiro método difundido que amarrou essa ideia a um formato padrão. Foi desenvolvido na Salesforce em 2017 por John Althouse, Jeff Atkinson e Josh Atkins e publicado como código aberto. Como descreve o repositório JA3 da Salesforce, o cálculo tem cinco passos:
- Da mensagem
ClientHellosão tirados cinco campos: versão do TLS, suítes de cifra, extensões, curvas (supported_groups) e formatos de ponto de curva elíptica. - Os valores de cada campo são convertidos para números decimais e juntados com
-na ordem em que aparecem na mensagem. - Os cinco campos são unidos com
,. Se um campo estiver vazio, o lugar dele fica vazio. - Valores GREASE (explicamos abaixo) não entram nas listas.
- Tira-se o hash MD5 da string resultante. Esse hash de 32 caracteres é o fingerprint JA3.
O exemplo do próprio repositório é este:
769,47-53-5-10-49161-49162-49171-49172-50-56-19-4,0-10-11,23-24-25,0
→ ada70206e40642a3e4461f35503241d5Lendo da esquerda: 769 significa TLS 1.0; depois vêm doze suítes de cifra, três extensões, três curvas e um único formato de ponto. Aqui o MD5 não serve para segurança, e sim para transformar uma string longa em uma chave pesquisável de tamanho fixo.
Duas observações: como clientes de TLS 1.3 escrevem o valor do TLS 1.2 no campo de versão, quase toda string JA3 atual começa com 771. A Salesforce arquivou o repositório em 1 de maio de 2025; ferramentas como o Wireshark continuam calculando o valor, mas o método não recebe mais manutenção.
O que é GREASE e por que o JA3 o ignora?
GREASE é um mecanismo de robustez definido na RFC 8701. O cliente acrescenta às suas listas de suítes de cifra, extensões e grupos alguns valores reservados escolhidos ao acaso, no padrão 0x0A0A, 0x1A1A … 0xFAFA. Esses valores não significam nada. O objetivo é testar sem parar se os servidores ignoram em silêncio valores que não reconhecem: um servidor defeituoso que derruba a conexão diante de um valor desconhecido é notado hoje, e não no dia em que um recurso novo do TLS entrar no ar.
Como os valores são sorteados, o mesmo navegador produziria um hash diferente a cada conexão se o JA3 os contasse. Por isso a documentação do método pede que os valores GREASE sejam pulados; no código abaixo, quem faz isso é a função is_grease.
Por que o Chrome embaralha a ordem das extensões?
O GREASE protege o conteúdo das listas, não a ordem delas. O fato de softwares de servidor e de equipamentos intermediários confiarem na ordem fixa de extensões do Chrome trazia o mesmo risco, então o time do Chrome tornou a ordem aleatória também. Segundo o registro no Chrome Platform Status, o recurso «TLS ClientHello extension permutation» passou a vir ligado por padrão no Chrome 110. A justificativa registrada não é fugir do fingerprint, e sim evitar que o ecossistema fique frágil: uma ordem fixa leva quem desenvolve servidores a reconhecer o Chrome e supor um comportamento específico, o que dificulta mudanças futuras no TLS. A RFC 8446 já diz que as extensões podem vir em qualquer ordem; a única exceção é a pre_shared_key, que precisa ficar por último quando está presente.
Como o JA3 junta as extensões na ordem da mensagem, essa mudança deixou instável o hash JA3 dos navegadores baseados em Chromium. Medimos com o ouvinte mais abaixo: 24 conexões seguidas de um navegador baseado em Chromium deram 24 hashes JA3 diferentes. Ao ordenar os números das extensões, todas tinham o mesmo conjunto; só a ordem mudava.
O que é o JA4 e qual a diferença para o JA3?
O JA4 é o formato mais novo, publicado pela FoxIO, que responde a esse problema. Segundo a especificação técnica do JA4, o fingerprint tem três partes no formato a_b_c. O exemplo do documento, t13d1516h2_8daaf6152771_e5627efa2ab1, se lê assim:
t: TLS sobre TCP (qseria QUIC ed, DTLS).13: TLS 1.3. O JA4 lê a versão na extensãosupported_versions, não no campo antigo.d: existe extensão SNI, ou seja, o cliente está se conectando a um nome de domínio (imostra que não há SNI).15e16: 15 suítes de cifra e 16 extensões, sem contar GREASE.h2: o primeiro e o último caractere do primeiro valor da lista ALPN, isto é, HTTP/2.8daaf6152771: os códigos hexadecimais das suítes de cifra são ordenados, passam por SHA-256 e ficam os 12 primeiros caracteres.e5627efa2ab1: os códigos de extensão são ordenados (sem SNI e ALPN), os algoritmos de assinatura são anexados na ordem original e o resultado é resumido do mesmo jeito.
A ordenação tira o efeito do embaralhamento das extensões. A primeira parte, legível, permite uma separação grosseira sem olhar os hashes: duas primeiras partes, uma terminando em h2 e a outra em 00 por não enviar ALPN, não vêm do mesmo software.
| JA3 | JA4 | |
|---|---|---|
| Quem publica | Salesforce (2017), repositório arquivado em 2025 | FoxIO, com desenvolvimento ativo |
| Formato | um único hash MD5 de 32 caracteres | a_b_c: prefixo legível + dois hashes SHA-256 encurtados |
| Ordem das extensões | a da mensagem | ordenada; não sofre com o embaralhamento |
| Versão do TLS | campo de versão antigo (771 mesmo no TLS 1.3) | extensão supported_versions |
| ALPN, SNI | aparecem só como número de extensão | os dois vêm escritos na primeira parte |
| Algoritmos de assinatura | não usados | entram na terceira parte |
| GREASE | ignorado | ignorado |
Segundo a nota de licença no repositório da FoxIO, o JA4, o fingerprint de cliente TLS, é aberto sob licença BSD 3-Clause; os demais membros da família (JA4S, JA4H, JA4X, JA4T e por aí vai) seguem uma licença própria da FoxIO.
Um proxy muda o fingerprint TLS?
Não. O motivo está em como um proxy transporta o tráfego HTTPS.
No proxy HTTP, o cliente primeiro envia ao proxy uma requisição CONNECT destino.com:443. O proxy abre uma conexão TCP até o destino, responde 200 Connection Established e a partir daí só repassa bytes. O ClientHello viaja dentro desse túnel: quem o produz é o seu cliente, quem o lê é o site de destino, e o proxy não muda o conteúdo nem o reescreve. No SOCKS5 é igual; o protocolo repassa a conexão TCP uma camada abaixo e nem sabe que os dados que carrega são TLS. Percorremos os dois protocolos passo a passo em Diferença entre SOCKS e HTTP proxy.
O resultado é que o site vê ao mesmo tempo o endereço IP do proxy e o fingerprint TLS do seu cliente. Usar Proxies HTTPS ou Proxies SOCKS5 não muda isso, e o proxy ser residencial, móvel ou de datacenter também não. Testamos com um proxy de teste local: o mesmo cliente curl se conectou ao ouvinte abaixo de forma direta, por um túnel HTTP CONNECT e por SOCKS5, e o ouvinte registrou a mesma string JA3 nas três vezes.
O único caso em que o fingerprint muda é quando há no meio um intermediário que encerra o TLS:
| O que está no meio | Quem estabelece o TLS com o destino? | Qual fingerprint o site vê? |
|---|---|---|
Proxy HTTP (túnel CONNECT) | Seu cliente | O do seu cliente |
| Proxy SOCKS5 | Seu cliente | O do seu cliente |
| VPN | Seu cliente | O do seu cliente |
| Gateway corporativo com inspeção TLS | O gateway | O do gateway |
| Antivírus com varredura HTTPS ligada | O antivírus | O do antivírus |
| Serviço que baixa a página no seu lugar | O cliente do serviço | O do cliente do serviço |
A quinta linha aconteceu na nossa própria máquina enquanto preparávamos este texto: o curl no Windows devolvia um fingerprint ao se conectar direto ao serviço de eco e outro ao passar pelo túnel do proxy local. A causa era a varredura HTTPS do antivírus, que refazia a conexão direta com a pilha TLS dele. Se o valor no serviço de eco não parece com a biblioteca que você esperava, veja quem assinou o certificado.
Como ver a sua própria string JA3?
O caminho mais curto é um serviço de eco: abra a página TLS do BrowserLeaks no navegador e você verá seus valores JA3 e JA4. Se quiser olhar no nível de pacote, o Wireshark calcula esses valores sozinho nos pacotes ClientHello; na referência de filtros de exibição os campos aparecem como tls.handshake.ja3 e tls.handshake.ja4.
Para ver o cálculo em si, você pode usar o script abaixo. Ele roda só com a biblioteca padrão do Python e não envia nada para fora: abre um ouvinte TCP cru na porta 8443, analisa a mensagem ClientHello de cada cliente que se conecta e imprime a string JA3 e o hash dela. Na inicialização ele conecta uma vez o próprio cliente urllib do Python. O ouvinte não completa o handshake, lê o primeiro pacote e fecha; um erro de conexão do lado do cliente é o esperado.
import hashlib
import socket
import threading
import urllib.request
HOST, PORT = "127.0.0.1", 8443
def is_grease(value):
# RFC 8701: 0x0a0a, 0x1a1a, ... 0xfafa
return (value & 0x0F0F) == 0x0A0A and (value >> 8) == (value & 0xFF)
def read_client_hello(conn):
data = b""
while len(data) < 5:
data += conn.recv(4096)
if data[0] != 22: # 22 = registro de handshake
raise ValueError("nao e um handshake TLS")
record_length = int.from_bytes(data[3:5], "big")
while len(data) < 5 + record_length:
chunk = conn.recv(4096)
if not chunk:
break
data += chunk
return data[5 : 5 + record_length]
def ja3_from_client_hello(hello):
if hello[0] != 1: # 1 = ClientHello
raise ValueError("nao e um ClientHello")
pos = 4 # tipo da mensagem (1) + tamanho (3)
version = int.from_bytes(hello[pos : pos + 2], "big")
pos += 2 + 32 # versao + random
pos += 1 + hello[pos] # session_id
size = int.from_bytes(hello[pos : pos + 2], "big")
pos += 2
ciphers = [int.from_bytes(hello[i : i + 2], "big") for i in range(pos, pos + size, 2)]
pos += size
pos += 1 + hello[pos] # compression_methods
end = pos + 2 + int.from_bytes(hello[pos : pos + 2], "big")
pos += 2
extensions, groups, point_formats = [], [], []
while pos < end:
ext_type = int.from_bytes(hello[pos : pos + 2], "big")
ext_size = int.from_bytes(hello[pos + 2 : pos + 4], "big")
body = hello[pos + 4 : pos + 4 + ext_size]
pos += 4 + ext_size
extensions.append(ext_type)
if ext_type == 10: # supported_groups
groups = [int.from_bytes(body[i : i + 2], "big") for i in range(2, len(body), 2)]
elif ext_type == 11: # ec_point_formats
point_formats = list(body[1:])
def join(values):
return "-".join(str(v) for v in values if not is_grease(v))
fields = [str(version), join(ciphers), join(extensions), join(groups), join(point_formats)]
ja3_text = ",".join(fields)
return ja3_text, hashlib.md5(ja3_text.encode()).hexdigest()
def own_python_client():
try:
urllib.request.urlopen(f"https://localhost:{PORT}", timeout=5)
except OSError:
pass # o ouvinte fecha sem responder, e o esperado
def main():
server = socket.create_server((HOST, PORT))
print(f"ouvindo em https://localhost:{PORT}, Ctrl+C para sair")
threading.Thread(target=own_python_client, daemon=True).start()
while True:
conn, _ = server.accept()
with conn:
try:
ja3_text, ja3_hash = ja3_from_client_hello(read_client_hello(conn))
except (ValueError, IndexError, OSError) as exc:
print("nao foi possivel ler:", exc)
continue
print(ja3_hash, ja3_text)
if __name__ == "__main__":
main()Com o script rodando, aponte clientes diferentes para o mesmo endereço a partir de outro terminal. Escreva localhost no endereço; um cliente que se conecta a um endereço IP não envia a extensão SNI e o fingerprint muda.
curl -k https://localhost:8443
node -e "require('https').get('https://localhost:8443', { rejectUnauthorized: false }).on('error', () => {})"Na nossa máquina (Windows 11, Python 3.13 com OpenSSL 3.0, Node.js 24 e curl 8 compilado com Schannel) a saída foi esta. Encurtamos o campo das suítes de cifra para melhorar a leitura:
331a436afb23d4e31134c11b301bdcb5 771,4866-4867-4865-…,0-11-10-35-16-22-23-49-13-43-45-51-21,29-23-30-25-24-256-257-258-259-260,0-1-2
2e6c64f66822fc35b6a7a128b557f1de 771,4866-4865-49196-…,0-43-13-35-10-11-16-51-49-23-65281-45,29-23-24,0
944d1e1858cd278718f8a46b65d3212f 771,4866-4867-4865-…,65281-0-11-10-35-22-23-13-43-45-51,4588-29-23-30-24-25-256-257,0-1-2A mesma máquina, o mesmo IP e três identidades distintas: na ordem, Python, curl e Node.js. Para o Python, o serviço de eco devolveu exatamente o mesmo hash, ou seja, o analisador funciona. O 4588 na linha do Node.js é o grupo híbrido pós-quântico de troca de chaves que aparece nos registros da IANA como X25519MLKEM768; esta versão do Python não o envia. No mesmo Node.js, https.get e o fetch embutido também deram valores JA3 diferentes, porque o fetch acrescenta a extensão ALPN: o fingerprint depende da biblioteca HTTP usada, não da linguagem. As diferenças entre bibliotecas do lado do Python nós comparamos em Comparativo entre HTTPX, Requests e AIOHTTP.
Para medir o efeito de um proxy o ouvinte não serve (um proxy remoto não alcança o seu localhost), então pergunte duas vezes ao serviço de eco:
import json
import urllib.request
PROXY = "http://user:pass@pr.proxynet.io:8000"
URL = "https://tls.browserleaks.com/json"
def fingerprint(opener):
with opener.open(URL, timeout=15) as response:
result = json.load(response)
return result["ja3_hash"], result["ja4"]
direct = urllib.request.build_opener(urllib.request.ProxyHandler({}))
proxied = urllib.request.build_opener(urllib.request.ProxyHandler({"https": PROXY}))
print("direto:", *fingerprint(direct))
print("proxy :", *fingerprint(proxied))Você verá os mesmos valores nas duas linhas; o que muda é só o endereço IP que o serviço enxerga.
Como o dono de um site usa esse dado?
Produtos de CDN e firewall expõem o valor JA3 ou JA4 como um campo ao lado de cada requisição. O dono do site usa esse campo ao escrever regras e ao revisar os registros. Usos típicos:
- Verificação de coerência. Se o
User-Agentdiz «Chrome» mas o fingerprint não bate com nenhuma versão conhecida do Chrome, o cabeçalho foi alterado. Sozinho não é prova definitiva, mas é um sinal forte que pesa na pontuação. O cabeçalho em si está em O que é User-Agent?. - Limite de requisições independente do IP. Se um tráfego espalhado por centenas de IPs carrega o mesmo fingerprint, o contador pode ser amarrado ao fingerprint em vez do IP. Um IP rotativo não zera esse contador.
- Reconhecer ferramentas conhecidas. Existem listas de fingerprints compiladas para famílias de malware e ferramentas de varredura; times de segurança as cruzam com os registros.
Também há limites. Um site que bloqueia o valor de um navegador atual bloqueia todos os visitantes que usam esse navegador. Atualizações do navegador mudam o valor, e gateways corporativos e antivírus colocam os fingerprints deles no meio. Por isso um fingerprint TLS não decide nada sozinho; é um dos sinais que alimentam a pontuação junto da reputação do IP e do comportamento. Essa pontuação como um todo está em Como funciona a detecção de bots?, e as camadas da Cloudflare em O que é o Cloudflare Precursor?.
O que isso significa para quem coleta dados?
Voltando à situação da introdução. O cliente Python diz na linha User-Agent que é Chrome, enquanto o ClientHello dele diz que é OpenSSL. O site vê a contradição no primeiro pacote. A reação certa é eliminar a contradição, não tentar escondê-la:
- Não diga que é um navegador que você não é. Deixe o
User-Agentdo seu script apresentar o script: um nome, uma versão e um endereço de contato. Um cliente que chega com identidade honesta, respeita orobots.txte trabalha devagar pode ser reconhecido pelo dono do site e entrar numa lista de permissões. As regras estão em O que é robots.txt e como ler o arquivo?. - Se existe uma API oficial, use. Uma requisição que chega com chave de API já tem identidade conhecida; a discussão sobre fingerprint some.
- Se a página realmente precisa de um navegador, use um de verdade. Quando você abre uma página desenhada por JavaScript com o Playwright dentro de um Chromium real, o seu cliente é mesmo aquele navegador; cabeçalhos, camada TLS e ambiente JavaScript concordam entre si. A instalação está em O que é Playwright e como usá-lo com proxy.
- Reduza o ritmo e peça permissão. Para um trabalho regular e de grande volume, escrever ao dono do site costuma ser a solução mais duradoura.
Os outros motivos de bloqueio, e os caminhos legítimos para eles, estão reunidos em Como fazer web scraping sem ser bloqueado.
Casos de uso
- Diagnosticar um
403no scraper: se com o mesmo IP o navegador passa e o script não, a diferença está quase certamente na identidade do cliente. Os códigos de status separamos em Códigos de status HTTP no web scraping, e o desenho geral está na nossa página de solução de extração de dados. - Separar o tráfego de bots no seu próprio site: agrupar os registros por fingerprint mostra o tráfego distribuído que o agrupamento por IP deixa passar.
- Apresentar o seu próprio crawler: uma versão fixa de biblioteca produz um fingerprint constante, e é assim que o seu crawler é reconhecido nos registros. A parte de infraestrutura está na nossa página de solução de web crawler.
- Acertar a expectativa sobre um proxy: Proxies residenciais muda a reputação do IP e a localização; a identidade do seu cliente continua sendo responsabilidade sua.
Erros comuns
- Achar que o cliente muda quando o
User-Agentmuda. O cabeçalho é texto; oClientHelloé o comportamento da biblioteca e sai antes do cabeçalho. - Esperar que o proxy mude o fingerprint TLS. Um proxy que faz túnel muda o IP e não encosta no handshake.
- Esperar que o hash JA3 fique fixo em um navegador baseado em Chromium. A ordem das extensões muda a cada conexão; para comparar, use JA4 ou uma lista de extensões ordenada.
- Aceitar o resultado do serviço de eco sem questionar. Um antivírus ou gateway corporativo que varre HTTPS mostra ao serviço o fingerprint dele mesmo.
- Usar
127.0.0.1na medição. Não vai SNI, e o valor sai diferente do das conexões reais.
Guia de decisão
| Situação | Recomendação |
|---|---|
O IP muda pelo proxy e mesmo assim vem 403 na primeira requisição | Olhe a identidade do cliente: o User-Agent e a biblioteca que você usa dizem a mesma coisa? |
| Você quer saber o valor JA3 ou JA4 do seu próprio cliente | Um serviço de eco ou o ouvinte local acima |
| Você quer agrupar o tráfego do Chrome nos seus registros | JA4, não JA3; não sofre com o embaralhamento de extensões |
| A página precisa de JavaScript e de um navegador real | Automação com navegador real (Playwright), ritmo razoável e o escopo que o site permite |
| O serviço de eco mostra um valor inesperado | Veja quem assinou o certificado; pode haver software encerrando o TLS no meio |
| Seu site recebe tráfego de bots distribuído | Amarre o limite de requisições ao par IP + fingerprint em vez do IP; não bloqueie por um único hash |
Perguntas frequentes
Qual a diferença entre JA3 e JA3S?
O JA3 é produzido a partir da mensagem ClientHello do cliente, e o JA3S a partir da mensagem ServerHello do servidor. Como um servidor responde de forma diferente a clientes diferentes, o JA3S não identifica o servidor sozinho; já a resposta dele ao mesmo cliente é sempre a mesma. Por isso times de segurança usam os dois em par.
Usar uma VPN muda o fingerprint TLS?
Não. A VPN leva o tráfego por um túnel criptografado, mas o handshake TLS com o site continua sendo feito pelo seu navegador ou pelo seu script. O site vê o endereço IP do servidor VPN e o fingerprint do seu cliente. A diferença entre as duas ferramentas está em Diferença entre proxy e VPN.
Um fingerprint TLS me identifica pessoalmente?
Sozinho, não. Todo mundo que roda a mesma versão de navegador no mesmo sistema operacional produz o mesmo valor. Uma identidade que chega perto de uma pessoa nasce da combinação desse valor com o endereço IP, os cookies e os sinais da camada de JavaScript.
Atualizar o navegador muda o fingerprint?
Pode mudar. Quando uma versão nova remove uma suíte de cifra ou acrescenta uma extensão, a lista e o hash mudam. Por isso as listas de fingerprints são mantidas versão a versão.
Uma janela anônima ou apagar os cookies afeta o fingerprint TLS?
Não. A mensagem ClientHello é produzida pela biblioteca TLS do navegador; histórico, cookies e tipo de janela não entram nessas listas.
O que faço se estou sendo bloqueado por causa do meu fingerprint?
Meça primeiro: veja qual valor aparece no serviço de eco e se há software encerrando o TLS no meio. Se você escreve um script, declare a sua identidade com honestidade, reduza o ritmo e use a API oficial ou o canal de permissão do site. Se o bloqueio acontece com um navegador comum, o problema quase certamente está na reputação do IP, e não no fingerprint.
Em resumo
O fingerprint TLS sai do ClientHello, o primeiro pacote, sem criptografia, de uma conexão criptografada. O JA3 junta na ordem as cinco listas dessa mensagem e tira o hash MD5; quando o Chrome passou a embaralhar a ordem das extensões, o hash ficou instável, e o JA4 resolveu isso ordenando as listas. O valor mostra o software, não a pessoa, sai antes dos cabeçalhos e nenhum proxy que faça túnel encosta nele: o proxy muda o IP e a identidade do cliente fica com você. Para somar o tipo de IP certo a uma identidade de cliente constante e honesta, dê uma olhada nos nossos serviços de proxy.




