curl-impersonate: um build especial do curl que pode imitar os principais navegadores
(github.com/lwthiker)- curl-impersonate é um build modificado do curl para realizar handshakes TLS e HTTP que se parecem com os do Chrome, Edge, Safari e Firefox, podendo ser usado como ferramenta de linha de comando e como biblioteca substituta do
libcurl - O Client Hello e as configurações de HTTP/2 de clientes e bibliotecas HTTP comuns diferem bastante dos navegadores reais, então alguns serviços web identificam o cliente pelo handshake TLS/HTTP e entregam conteúdo diferente
- A implementação usa NSS para Firefox e BoringSSL para navegadores baseados em Chrome, além de mudanças em extensões TLS, opções SSL, configurações de HTTP/2 e aplicação de flags não padrão como
--ciphers,--curvese cabeçalhos - Os alvos suportados incluem Chrome 99~116, Chrome 99 para Android, Edge 99·101, Firefox 91 ESR~117 e Safari 15.3·15.5, com wrapper scripts e nomes de alvo fornecidos para cada um
- Na linha de comando, execute
curl_chrome116; na integração por biblioteca, aplique comcurl_easy_impersonate()ou, no Linux, comLD_PRELOADeCURL_IMPERSONATEem apps existentes que usamlibcurl
O problema que o curl-impersonate resolve
- curl-impersonate é um projeto que faz um build especial do curl para que ele possa imitar os quatro principais navegadores: Chrome, Edge, Safari e Firefox
- Ele consegue realizar handshakes TLS e HTTP idênticos aos dos navegadores reais
- Há duas formas de uso
- uma ferramenta de linha de comando parecida com o curl comum
- uma biblioteca que pode ser integrada no lugar do
libcurlexistente
Por que isso é necessário
- Quando um cliente HTTP acessa um site com TLS, primeiro ele realiza um handshake TLS
- A primeira mensagem do handshake TLS é o Client Hello, e o Client Hello gerado pela maioria dos clientes e bibliotecas HTTP difere bastante do dos navegadores reais
- Se o servidor usa HTTP/2, além do handshake TLS também ocorre um handshake HTTP/2, no qual várias configurações são trocadas
- As configurações de HTTP/2 da maioria dos clientes e bibliotecas HTTP também diferem das dos navegadores reais
- Alguns serviços web usam essas diferenças para identificar o cliente que está se conectando e entregar conteúdo diferente para cada cliente
- esse método é chamado de TLS fingerprinting e HTTP/2 fingerprinting
- o README afirma que o uso amplo dessas técnicas tornou a web menos aberta, menos privada e mais restrita a clientes web específicos
Como funciona
- O
curlrecebe vários patches para parecer um navegador - As principais mudanças são as seguintes
- a versão Firefox compila o curl com NSS, a biblioteca TLS usada pelo Firefox, em vez de OpenSSL
- a versão Chrome é compilada com BoringSSL, a biblioteca TLS do Google
- muda a forma como o curl configura várias extensões TLS e opções SSL
- adiciona suporte a novas extensões TLS
- altera as configurações usadas em conexões HTTP/2
- executa o curl com flags não padrão como
--ciphers,--curvese alguns cabeçalhos-H
- Como resultado, do ponto de vista da rede, o curl passa a parecer idêntico a um navegador real
- A explicação técnica completa está em part a, part b
Navegadores suportados e nomes de alvo
- A lista de navegadores suportados também está disponível em
browsers.json - Alvos suportados da família Chrome
- Chrome 99, 100, 101, 104, 107, 110, 116 no Windows 10
- Chrome 99 no Android 12
- Edge 99, 101 no Windows 10
- Safari 15.3 no MacOS Big Sur
- Safari 15.5 no MacOS Monterey
- Alvos suportados do Firefox
- Firefox 91 ESR, 95, 98, 100, 102, 109, 117 no Windows 10
- Cada alvo suportado tem um nome de alvo e um wrapper script
- exemplo: o alvo
chrome116é executado com o wrapper scriptcurl_chrome116 - exemplo: o alvo
ff117é executado com o wrapper scriptcurl_ff117
- exemplo: o alvo
Uso básico
- Para cada navegador suportado existe um wrapper script que executa o
curl-impersonatecom os cabeçalhos e flags necessários - Exemplo de execução
curl_chrome116 https://www.wikipedia.org - Se você adicionar flags de linha de comando, elas serão passadas ao curl
- Algumas flags podem alterar a assinatura TLS do curl e permitir sua detecção
- O wrapper script usa um conjunto padrão de cabeçalhos HTTP
- para mudar os cabeçalhos, você pode editar o wrapper script conforme seu objetivo
- Mais opções estão no uso avançado da
libcurl-impersonatecomo biblioteca
Instalação e formas de distribuição
- Por motivos técnicos, o
curl-impersonateexiste em duas versões- versão chrome: usada para imitar Chrome, Edge e Safari
- versão firefox: usada para imitar Firefox
- Binários pré-compilados para Linux e macOS Intel são oferecidos em GitHub releases
- Antes de usar os binários pré-compilados, é preciso instalar NSS e os certificados CA
- Ubuntu:
sudo apt install libnss3 nss-plugin-pem ca-certificates - Red Hat/Fedora/CentOS:
yum install nss nss-pem ca-certificates - Archlinux:
pacman -S nss ca-certificates - macOS:
brew install nss ca-certificates
- Ubuntu:
- O sistema também precisa de zlib
- o zlib quase sempre está presente, mas pode faltar em alguns sistemas mínimos
- Os binários Linux pré-compilados são gerados para sistemas Ubuntu
- se ocorrer erro de verificação de certificado em outra distribuição, talvez seja necessário informar ao curl a localização dos certificados CA
curl_chrome116 https://www.wikipedia.org --cacert /etc/ssl/certs/ca-bundle.crt - Para compilar a partir do código-fonte, consulte INSTALL.md
Docker e pacotes
- Imagens Docker baseadas em Alpine Linux e Debian são oferecidas no Docker Hub
- As imagens Docker incluem os binários e todos os wrapper scripts
- Exemplo
# Firefox version, Alpine Linux docker pull lwthiker/curl-impersonate:0.6-ff docker run --rm lwthiker/curl-impersonate:0.6-ff curl_ff109 https://www.wikipedia.org # Chrome version, Alpine Linux docker pull lwthiker/curl-impersonate:0.6-chrome docker run --rm lwthiker/curl-impersonate:0.6-chrome curl_chrome110 https://www.wikipedia.org - Usuários de Archlinux podem usar pacotes AUR
- pacote pré-compilado: curl-impersonate-bin, libcurl-impersonate-bin
- pacotes com build a partir do código-fonte: curl-impersonate-chrome, curl-impersonate-firefox
- Uma fórmula Homebrew não oficial para Mac é oferecida apenas para Chrome
brew tap shakacode/brew brew install curl-impersonate
Uso avançado de libcurl-impersonate
libcurl-impersonate.soé uma libcurl compilada com as mesmas modificações docurl-impersonatede linha de comando- Há uma função extra de API
CURLcode curl_easy_impersonate(struct Curl_easy *data, const char * target, int default_headers); - Quando chamada com um nome de alvo como
chrome116, ela configura internamente as opções e os cabeçalhos que o wrapper script definiria - Se
default_headersfor 0, a lista interna de cabeçalhos HTTP não será configurada- nesse caso, o usuário deve fornecer os cabeçalhos manualmente com a opção comum
CURLOPT_HTTPHEADERdo libcurl
- nesse caso, o usuário deve fornecer os cabeçalhos manualmente com a opção comum
curl_easy_impersonate()configura várias opções do libcurlCURLOPT_HTTP_VERSIONCURLOPT_SSLVERSION,CURLOPT_SSL_CIPHER_LIST,CURLOPT_SSL_EC_CURVES,CURLOPT_SSL_ENABLE_NPN,CURLOPT_SSL_ENABLE_ALPNCURLOPT_HTTPBASEHEADER, uma opção não padrão do projetoCURLOPT_HTTP2_PSEUDO_HEADERS_ORDER,CURLOPT_HTTP2_NO_SERVER_PUSH, opções HTTP/2 não padrão do projetoCURLOPT_SSL_ENABLE_ALPS,CURLOPT_SSL_SIG_HASH_ALGS,CURLOPT_SSL_CERT_COMPRESSION,CURLOPT_SSL_ENABLE_TICKET, opções TLS não padrão do projetoCURLOPT_SSL_PERMUTE_EXTENSIONS, outra opção TLS não padrão do projeto
- Depois disso, se você chamar
curl_easy_setopt()com qualquer uma dessas opções, o valor definido porcurl_easy_impersonate()será sobrescrito
Aplicando em apps existentes com libcurl
- Se a aplicação já usa
libcurl, no Linux é possível trocar a biblioteca existente em tempo de execução comLD_PRELOAD - Defina a variável de ambiente
CURL_IMPERSONATEpara aplicar a imitação automaticamenteLD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 my_app CURL_IMPERSONATEtem dois efeitoscurl_easy_impersonate()é chamada automaticamente quando um novo handle curl é criado comcurl_easy_init()curl_easy_impersonate()também é chamada automaticamente apóscurl_easy_reset()
- Se você precisar de controle detalhado sobre os cabeçalhos HTTP, desative a lista interna de cabeçalhos com
CURL_IMPERSONATE_HEADERS=noe configure-os manualmenteLD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 CURL_IMPERSONATE_HEADERS=no my_app - O método com
LD_PRELOADnão funciona com o próprio curl- porque a ferramenta curl sobrescreve as configurações TLS
- no caso do curl, é preciso usar o wrapper script
Estrutura do repositório e contribuição
- O repositório tem duas pastas principais
- O diretório Firefox, por exemplo, inclui os seguintes arquivos
- Dockerfile: usado para compilar o
curl-impersonatecom todas as dependências - curl_ff91esr, curl_ff95, curl_ff98: wrapper scripts que executam com as flags corretas
- curl-impersonate.patch: o principal patch que faz o curl usar as mesmas extensões TLS do Firefox e permite compilação estática com libnghttp2 e libnss
- Dockerfile: usado para compilar o
- tests/signatures é um banco de dados YAML com assinaturas conhecidas de navegadores que podem ser imitadas
- Os patches reais do curl são mantidos em um repositório separado, derivado do upstream do curl
- as mudanças para Firefox estão no branch impersonate-firefox
- as mudanças para Chrome estão no branch impersonate-chrome
1 comentários
Opiniões no Hacker News
Há um fork com várias melhorias em relação ao original e mantido ativamente: https://github.com/lexiforest/curl-impersonate
Também há bindings para usuários de Python: https://github.com/lexiforest/curl_cffi
Paradoxalmente, essa requisição provavelmente colocaria menos carga no servidor do que um navegador certificado; dá para pensar que essa é a distopia sobre a qual nos alertavam nos anos 90. Fico curioso para saber quem aqui conseguiria citar o nome de uma empresa que criou essa situação, ao mesmo tempo em que se posiciona como uma boa contribuinte da comunidade open source/hacker
Espero que o Ladybird ganhe força no futuro. No momento ele usa o cURL oficial para networking, e essa abordagem pode ter alguns obstáculos
Por exemplo, pelo que sei, o cURL ainda tem algumas limitações e não consegue lidar com WebSocket sobre h2. Por outro lado, se surgir um motor de navegador em crescimento, o tráfego normal também passaria a ter a mesma impressão digital do cURL padrão, o que poderia eliminar esse caminho de fingerprinting
Também é um bom teste para identificar quais recursos faltam ao cURL com base em fluxos de trabalho reais de navegadores
Nos últimos meses, aumentou muito o nível de fingerprinting e de “abuso” de comportamentos definidos pela implementação, provavelmente como uma tentativa de matar outros motores de navegador. Os incumbentes não gostam nem um pouco de concorrência
O outro lado tenta vender isso como “DDoS de bots de IA”, mas fico me perguntando quanto disso foi criado por eles mesmos
Gosto deste curl, mas me preocupa que, quando algum componente assume o papel de truque para “acompanhar” os outros, acabe acumulando um fardo de “compatibilidade” difícil de manter
O ideal seria simplesmente poder dizer: “olá, eu sou o curl, me deixe entrar”
Claro, o problema está nos servidores exigentes com o código de vestimenta, e esse problema também nasce dos golpistas que entram disfarçados, então é um ciclo de ovo e galinha
[0] https://cybershow.uk/episodes.php?id=39
Além disso, há um grande risco de segurança no fato de ele ter sido redesenhado em C++, uma linguagem comprovadamente insegura
Será que também configuraram
IP_TTLpara combinar o valor de TTL com a plataforma que estão tentando imitar?Caso contrário, ainda é possível fazer algum fingerprinting na camada IP. Se o valor de TTL na camada IP for menor que 64, fica claro que não está rodando em um Windows moderno, ou então é um Windows moderno com o TTL padrão alterado. Isso porque o TTL padrão dos pacotes no Windows moderno começa em 128, enquanto na maioria das outras plataformas começa em 64
Como outras plataformas também se comunicam pela internet sem problemas, pacotes IP vindos de um Windows moderno sempre aparecerão para o lado remoto com TTL de 64 ou mais, provavelmente um pouco acima de 64. Ainda assim, fingerprinting na camada IP é difícil, mas não impossível
https://en.wikipedia.org/wiki/TCP/IP_stack_fingerprinting
Espera, se o handshake TLS parece diferente, não daria para filtrar no nível do nginx tráfego que afirma ser um navegador web, mas que na verdade é um script Python/PHP?
Por exemplo, quando usa um user agent do Chrome, mas não é um navegador real. Grande parte do tráfego de bots maliciosos deve se encaixar nisso, então seria bom se desse para simplesmente bloquear
O funcionamento está detalhado em https://github.com/FoxIO-LLC/ja4/blob/main/technical_details..., e também há um módulo para Nginx: https://github.com/FoxIO-LLC/ja4-nginx-module
Se você não estiver sofrendo um ataque naquele momento, não deve usar uma lista de permissões de fingerprints TLS
É uma ferramenta legal, mas não deveria importar se o cliente é um navegador ou não. É amargo que, na prática, uma ferramenta dessas seja necessária
Adicionei ao Chrome uma extensão de user agent, mudei para IE e tentei de novo; funcionou, e todos os recursos do site também estavam intactos. Então foi amargo e irritante ao mesmo tempo. Provavelmente aquele órgão do governo criou o site 25 anos atrás e nunca mais o atualizou
Esse tipo de gatekeeping também me deixa amargo. Pelo que entendi, um navegador personalizado ou user agent criado por você mesmo jamais vai funcionar em sites do tipo Cloudflare até que tenha influência, dinheiro, número de usuários ou algo assim em quantidade suficiente para convencê-los
Esta ferramenta é bem boa para usar em operações de red team combinada com pequenos scripts bash e GNU parallel
Foi útil para mapear, dentro de faixas de endereços definidas no escopo, endpoints HTTPS que, por vários motivos, só respondiam a um navegador de verdade ou só respondiam quando a configuração de SNI estava correta. Opções comuns do curl, como
-Hpara mascarar headers, também podem ser usadas normalmentePost Show HN da época: https://news.ycombinator.com/item?id=30378562
Sempre fico com sentimentos ambivalentes quando algo assim aparece por aqui. Por um lado, é bom ver que ainda há um pouco de espírito de rebeldia e independência entre as pessoas
Por outro lado, como em outros projetos em que “liberdade é instabilidade”, se isso chamar atenção indesejada, a situação pode piorar para quem depende dele. Escrever um navegador é difícil, e os atores dominantes continuam tornando isso ainda mais difícil
Não vejo isso como uma questão de rebeldia. Software se tornar identificável por fingerprint corrói a privacidade e a diversidade de software
Sinto um pouco de falta dos tempos simples em que, se um site aceitava bots, permitia; se não gostava deles, bloqueava o user agent
Se são só 3 patches e um wrapper de shell, é algo em que o Daniel poderia botar a mão no código. Pessoalmente, acho que isso deveria necessariamente entrar no curl mainline