3 pontos por GN⁺ 2025-04-04 | 1 comentários | Compartilhar no WhatsApp
  • 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, --curves e 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 com curl_easy_impersonate() ou, no Linux, com LD_PRELOAD e CURL_IMPERSONATE em apps existentes que usam libcurl

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 libcurl existente

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 curl recebe 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, --curves e 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 script curl_chrome116
    • exemplo: o alvo ff117 é executado com o wrapper script curl_ff117

Uso básico

  • Para cada navegador suportado existe um wrapper script que executa o curl-impersonate com 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-impersonate como biblioteca

Instalação e formas de distribuição

  • Por motivos técnicos, o curl-impersonate existe 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
  • 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
  • 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 do curl-impersonate de 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_headers for 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_HTTPHEADER do libcurl
  • curl_easy_impersonate() configura várias opções do libcurl
    • CURLOPT_HTTP_VERSION
    • CURLOPT_SSLVERSION, CURLOPT_SSL_CIPHER_LIST, CURLOPT_SSL_EC_CURVES, CURLOPT_SSL_ENABLE_NPN, CURLOPT_SSL_ENABLE_ALPN
    • CURLOPT_HTTPBASEHEADER, uma opção não padrão do projeto
    • CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, CURLOPT_HTTP2_NO_SERVER_PUSH, opções HTTP/2 não padrão do projeto
    • CURLOPT_SSL_ENABLE_ALPS, CURLOPT_SSL_SIG_HASH_ALGS, CURLOPT_SSL_CERT_COMPRESSION, CURLOPT_SSL_ENABLE_TICKET, opções TLS não padrão do projeto
    • CURLOPT_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 por curl_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 com LD_PRELOAD
  • Defina a variável de ambiente CURL_IMPERSONATE para aplicar a imitação automaticamente
    LD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 my_app
    
  • CURL_IMPERSONATE tem dois efeitos
    • curl_easy_impersonate() é chamada automaticamente quando um novo handle curl é criado com curl_easy_init()
    • curl_easy_impersonate() também é chamada automaticamente após curl_easy_reset()
  • Se você precisar de controle detalhado sobre os cabeçalhos HTTP, desative a lista interna de cabeçalhos com CURL_IMPERSONATE_HEADERS=no e configure-os manualmente
    LD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 CURL_IMPERSONATE_HEADERS=no my_app
    
  • O método com LD_PRELOAD nã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
    • chrome: scripts e patches para gerar o build da versão Chrome do curl-impersonate
    • firefox: scripts e patches para gerar o build da versão Firefox do curl-impersonate
  • O diretório Firefox, por exemplo, inclui os seguintes arquivos
    • Dockerfile: usado para compilar o curl-impersonate com 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
  • 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

1 comentários

 
GN⁺ 2025-04-04
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

    • De certa forma, é natural que um programa para “fazer o curl parecer um navegador” seja patrocinado por um serviço de bypass de detecção de bots
    • Também há um módulo que integra isso totalmente à biblioteca requests do Python: https://github.com/el1s7/curl-adapter
    • É estranho ter que acompanhar tecnologias “avançadas” que mudam mais rápido do que a gente consegue virar o pescoço só para fazer uma requisição simples parecer um dos três grandes navegadores web “certificados”
      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

    • Tomara que o uso do cURL pelo Ladybird sirva de impulso para melhorar o próprio cURL em pontos como, por exemplo, o WebSocket sobre h2 mencionado
      Também é um bom teste para identificar quais recursos faltam ao cURL com base em fluxos de trabalho reais de navegadores
    • Sobre a parte de que “se houver um motor de navegador em crescimento, esse caminho de fingerprinting pode desaparecer”, pelo que vi na Cloudflare e similares, é quase o oposto
      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
    • Quando conversei com esse pessoal [0], falamos de várias diferenças estranhas de implementação usadas para criar assinaturas, incluindo até elementos da pilha TCP que apps em espaço de usuário não conseguem controlar
      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
    • Espero que isso faça o Ladybird passar a oferecer suporte a URLs ftp
    • O Ladybird não tem recursos para competir com os navegadores atuais. Teve boa divulgação, mas faltam vantagens ou uma razão de existir em comparação com o Chromium
      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_TTL para 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

    • Isso só é difícil quando se usa PaaS/IaaS que não oferece acesso de baixo nível à pilha TCP/IP. Se você opera seu próprio servidor, fingerprinting de todo tipo de atributo TCP/IP é muito fácil
      https://en.wikipedia.org/wiki/TCP/IP_stack_fingerprinting
    • O valor de TTL dos pacotes recebidos não varia conforme as condições da rede? O servidor consegue recuperar o valor original do cliente?
    • Por que o TTL foi projetado para diminuir, e não para aumentar? Em geral, não se espera que quem roteia o tráfego decida se e como ele será roteado?
  • 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

    • A Cloudflare usa fingerprints TLS JA3/JA4, que são hashes de vários parâmetros do handshake TLS
      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
    • Basicamente, é isso que empresas de segurança como a Cloudflare fazem; além disso, elas aplicam ainda mais fingerprinting, como desafios JavaScript que verificam o interpretador JavaScript/DOM
    • É possível, e sites reais fazem isso, mas é bem ruim. A confiabilidade é baixa e acaba bloqueando todo mundo que não usa o Chrome mais recente no Windows mais recente
      Se você não estiver sofrendo um ataque naquele momento, não deve usar uma lista de permissões de fingerprints TLS
    • A ferramenta do artigo parece servir exatamente para evitar esse tipo de bloqueio
  • É 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

    • Cerca de 6 meses atrás, entrei em um site de leilões do governo que exigia Internet Explorer. Era realmente Internet Explorer, e o site também estava ativo, com os dados dos leilões atualizados
      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
    • Você só pode entrar no site se usar o software que aprovamos. Todo o resto é considerado malicioso. Mostre os documentos!
      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 -H para mascarar headers, também podem ser usadas normalmente

  • Post Show HN da época: https://news.ycombinator.com/item?id=30378562

    • Naquele momento, em 2022, era exclusivo para Firefox
  • 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

    • Parece que os desenvolvedores de navegadores querem que os navegadores sejam identificáveis por fingerprint, mas isso é mais algo que surge naturalmente quando pessoas diferentes implementam as coisas de formas diferentes
      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

    • Naquela época, os sites não consumiam tantos recursos quanto hoje. Vejo a reação negativa contra bots mais como um efeito colateral de expectativas excessivamente pesadas em relação à experiência web
  • 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