3 ポイント 投稿者 GN⁺ 2025-04-04 | 1件のコメント | WhatsAppで共有
  • curl-impersonateは、Chrome、Edge、Safari、Firefoxのように見えるTLSおよびHTTPハンドシェイクを行うよう修正されたcurlビルドで、CLIツールおよびlibcurl代替ライブラリとして利用可能
  • 一般的なHTTPクライアントやライブラリのClient HelloおよびHTTP/2設定は実際のブラウザと大きく異なるため、一部のWebサービスはTLS/HTTPハンドシェイクでクライアントを識別し、異なるコンテンツを提供する
  • 実装はFirefox向けにNSS、Chrome系向けにBoringSSLを使用し、TLS拡張・SSLオプション・HTTP/2設定の変更、--ciphers--curves、ヘッダーなどの非デフォルトフラグの適用で構成される
  • 対応対象はChrome 99〜116、Android Chrome 99、Edge 99・101、Firefox 91 ESR〜117、Safari 15.3・15.5で、各対象ごとにwrapper scriptとtarget nameが提供される
  • コマンドラインではcurl_chrome116を実行し、ライブラリ統合ではcurl_easy_impersonate()またはLinuxのLD_PRELOADCURL_IMPERSONATEで既存のlibcurl利用アプリに適用できる

curl-impersonateが解決する問題

  • curl-impersonateは、curlを特別にビルドして、Chrome、Edge、Safari、Firefoxの4大ブラウザを偽装できるようにしたプロジェクト
  • TLSとHTTPハンドシェイクを実際のブラウザと同一に実行できる
  • 利用方法は2つある
    • 通常のcurlに近いコマンドラインツール
    • 既存のlibcurlの代わりに統合できるライブラリ

なぜ必要か

  • HTTPクライアントがTLS対応Webサイトに接続すると、まずTLSハンドシェイクを行う
  • TLSハンドシェイクの最初のメッセージはClient Helloであり、多くのHTTPクライアントやライブラリが生成するClient Helloは実際のブラウザと大きく異なる
  • サーバーがHTTP/2を使用する場合、TLSハンドシェイクに加えてHTTP/2ハンドシェイクも行われ、そこでさまざまな設定が交換される
  • 多くのHTTPクライアントやライブラリのHTTP/2設定も実際のブラウザと異なる
  • 一部のWebサービスはこうした違いを利用して接続クライアントを識別し、クライアントごとに異なるコンテンツを提供する
    • この方式はTLS fingerprintingおよびHTTP/2 fingerprintingと呼ばれる
    • READMEでは、この方式の広範な利用によってWebがより開放的でなく、よりプライベートでなく、特定のWebクライアントにより限定されるものになったと述べている

仕組み

  • curlはブラウザのように見えるよう大幅にパッチが当てられている
  • 主な変更点は次のとおり
    • Firefox版はOpenSSLの代わりに、Firefoxが使用するTLSライブラリであるNSSでcurlをコンパイルする
    • Chrome版はGoogleのTLSライブラリであるBoringSSLでコンパイルする
    • curlが各種TLS拡張やSSLオプションを設定する方法を変更する
    • 新しいTLS拡張のサポートを追加する
    • HTTP/2接続で使用する設定を変更する
    • --ciphers--curves、一部の-Hヘッダーなど、非デフォルトフラグ付きでcurlを実行する
  • その結果、ネットワークの観点ではcurlが実際のブラウザと同一に見える
  • 技術的な詳細説明はpart apart bにある

対応ブラウザと対象名

  • 対応ブラウザ一覧はbrowsers.jsonにも記載されている
  • Chrome系の対応対象
    • Windows 10上のChrome 99、100、101、104、107、110、116
    • Android 12上のChrome 99
    • Windows 10上のEdge 99、101
    • MacOS Big Sur上のSafari 15.3
    • MacOS Monterey上のSafari 15.5
  • Firefoxの対応対象
    • Windows 10上のFirefox 91 ESR、95、98、100、102、109、117
  • 各対応対象にはtarget nameとwrapper scriptがある
    • 例: chrome116 targetはcurl_chrome116 wrapper scriptで実行する
    • 例: ff117 targetはcurl_ff117 wrapper scriptで実行する

基本的な使い方

  • 各対応ブラウザごとに、必要なヘッダーとフラグを含めてcurl-impersonateを実行するwrapper scriptがある
  • 実行例
    curl_chrome116 https://www.wikipedia.org
    
  • コマンドラインフラグを追加するとcurlに渡される
  • 一部のフラグはcurlのTLS signatureを変更し、検出される可能性がある
  • wrapper scriptはデフォルトのHTTPヘッダーセットを使用する
    • ヘッダーを変更したい場合は、目的に合わせてwrapper scriptを修正できる
  • より多くのオプションは、libcurl-impersonateをライブラリとして使う高度な利用方法に含まれる

インストールと配布方法

  • 技術的な理由により、curl-impersonateには2つのバージョンがある
    • chrome版: Chrome、Edge、Safariの偽装に使用
    • firefox版: Firefoxの偽装に使用
  • LinuxおよびmacOS Intel向けの事前コンパイル済みバイナリはGitHub releasesで提供される
  • 事前コンパイル済みバイナリを使用する前に、NSSと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
  • システムにはzlibも必要
    • zlibはほぼ常に存在するが、一部の最小構成システムにはない場合がある
  • 事前コンパイル済みLinuxバイナリはUbuntu向けにビルドされている
    • 他のディストリビューションで証明書検証エラーが出る場合、CA証明書の場所をcurlに指定する必要があるかもしれない
    curl_chrome116 https://www.wikipedia.org --cacert /etc/ssl/certs/ca-bundle.crt
    
  • ソースからのビルドはINSTALL.mdを参照

Dockerとパッケージ

  • Alpine LinuxおよびDebianベースのDockerイメージがDocker Hubで提供される
  • Dockerイメージにはバイナリとすべてのwrapper scriptが含まれる
  • # 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
    
  • ArchlinuxユーザーはAURパッケージを利用できる
  • Mac向けの非公式Homebrew formulaはChrome専用で提供される
    brew tap shakacode/brew
    brew install curl-impersonate
    

libcurl-impersonateの高度な使い方

  • libcurl-impersonate.soは、コマンドライン版curl-impersonateと同じ変更を加えてコンパイルされたlibcurl
  • 追加のAPI関数がある
    CURLcode curl_easy_impersonate(struct Curl_easy *data, const char * target,
                                   int default_headers);
    
  • chrome116のようなtarget nameで呼び出すと、wrapper scriptが設定していたオプションとヘッダーを内部で設定する
  • default_headersが0の場合、組み込みのHTTPヘッダー一覧は設定しない
    • ユーザーが通常のCURLOPT_HTTPHEADER libcurlオプションで直接ヘッダーを指定する必要がある
  • curl_easy_impersonate()は複数のlibcurlオプションを設定する
    • CURLOPT_HTTP_VERSION
    • CURLOPT_SSLVERSION, CURLOPT_SSL_CIPHER_LIST, CURLOPT_SSL_EC_CURVES, CURLOPT_SSL_ENABLE_NPN, CURLOPT_SSL_ENABLE_ALPN
    • プロジェクト用の非標準オプションであるCURLOPT_HTTPBASEHEADER
    • プロジェクト用の非標準HTTP/2オプションであるCURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, CURLOPT_HTTP2_NO_SERVER_PUSH
    • プロジェクト用の非標準TLSオプションであるCURLOPT_SSL_ENABLE_ALPS, CURLOPT_SSL_SIG_HASH_ALGS, CURLOPT_SSL_CERT_COMPRESSION, CURLOPT_SSL_ENABLE_TICKET
    • プロジェクト用の非標準TLSオプションであるCURLOPT_SSL_PERMUTE_EXTENSIONS
  • その後でcurl_easy_setopt()を使って上記オプションのいずれかを呼ぶと、curl_easy_impersonate()が設定した値を上書きする

既存のlibcurlアプリへの適用

  • アプリケーションがすでにlibcurlを使っている場合、LinuxではLD_PRELOADで既存ライブラリを実行時に差し替えられる
  • CURL_IMPERSONATE環境変数を設定して自動偽装を適用する
    LD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 my_app
    
  • CURL_IMPERSONATEには2つの効果がある
    • curl_easy_init()で新しいcurlハンドルが作られるたびにcurl_easy_impersonate()が自動で呼び出される
    • curl_easy_reset()の後にもcurl_easy_impersonate()が自動で呼び出される
  • HTTPヘッダーを細かく制御する必要がある場合は、CURL_IMPERSONATE_HEADERS=noで組み込みヘッダー一覧を無効化し、自分で設定する
    LD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 CURL_IMPERSONATE_HEADERS=no my_app
    
  • LD_PRELOAD方式はcurl自体には動作しない
    • curlツールがTLS設定を上書きするため
    • curlにはwrapper scriptを使う必要がある

リポジトリ構成と貢献

  • リポジトリには2つの主要フォルダがある
    • chrome: Chrome版curl-impersonateビルド用のスクリプトとパッチ
    • firefox: Firefox版curl-impersonateビルド用のスクリプトとパッチ
  • Firefoxディレクトリの例には次のファイルが含まれる
    • Dockerfile: すべての依存関係込みでcurl-impersonateをビルドするために使用
    • curl_ff91esrcurl_ff95curl_ff98: 正しいフラグで実行するwrapper script
    • curl-impersonate.patch: curlがFirefoxと同じTLS拡張を使うようにする主要パッチで、libnghttp2とlibnssで静的コンパイルされるようにする
  • tests/signaturesは、偽装可能な既知ブラウザsignatureのYAMLデータベース
  • 実際のcurlパッチは、upstream curlからforkされた別リポジトリで管理されている

1件のコメント

 
GN⁺ 2025-04-04
Hacker News の意見
  • オリジナルより改善点がかなり多く、活発にメンテナンスされているフォークがある: https://github.com/lexiforest/curl-impersonate
    Python ユーザー向けのバインディングもある: https://github.com/lexiforest/curl_cffi

    • 「curl をブラウザのように見せる」プログラムがボット検知回避サービスにスポンサーされているのは、ある意味自然なこと
    • これを Python の requests ライブラリと完全に統合するモジュールもある: https://github.com/el1s7/curl-adapter
    • 「認証済み」の三大 Web ブラウザの1つに見える単純なリクエストを1つ作るために、首を回すより速く変わる「高度な」技術を追いかけなければならないなんて奇妙だ
      皮肉なことに、そのリクエストは認証済みブラウザよりサーバー負荷が低いはずなのに、90年代に警告されていたディストピアとはこういうものなのかと思う。善良なオープンソース/ハッカーコミュニティの貢献者という立場を取りながら、この状況を作ったある会社の名前を、ここで誰が挙げられるのか気になる
  • 今後 Ladybird が勢いを得てほしい。現在ネットワーク処理には正式な cURL を使っているが、この方法には難所があるかもしれない
    例えば cURL にはまだいくつか制約があり、h2 上の WebSocket を扱えないと理解している。一方で成長中のブラウザエンジンが生まれれば、正規のトラフィックも標準 cURL と同じフィンガープリントを持つようになり、このフィンガープリンティング経路が消える可能性もある

    • Ladybird の cURL 利用が、例えば言及した h2 上の WebSocket のような部分で cURL 自体を改善するきっかけになるとよい
      実際のブラウザのワークフロー基準で、cURL にどんな機能が欠けているかを確認する良い試金石でもある
    • 「成長中のブラウザエンジンがあれば、このフィンガープリンティング経路が消える可能性もある」という部分は、CloudFlare などで見た限りでは、ほぼ正反対だ
      この数か月でフィンガープリンティングと実装定義の動作を「悪用」するレベルが大きく増えており、おそらく他のブラウザエンジンを潰そうとする試みに見える。既存の強者は競争をまったく好まない
      相手側はこれを「AI ボットによる DDoS」として装おうとするが、そのうちどれだけが自分たちの作った問題なのか疑問だ
    • この人たちと話したとき [0]、署名を作るためのさまざまな奇妙な実装差を扱っており、ユーザー空間アプリが制御できない TCP スタック要素まで含まれていた
      この curl は気に入っているが、何らかのコンポーネントが「追いつく」ためにごまかし役を担うと、メンテナンスしにくい「互換性」の重荷が積み上がるのではないかと心配している
      理想的には、単に「こんにちは、私は curl です。入れてください」と言えるべきだ
      もちろん問題はドレスコードにうるさいサーバー側にあり、その問題もまた変装して入ってくる詐欺師たちのせいで生じるので、鶏と卵のような循環になっている
      [0] https://cybershow.uk/episodes.php?id=39
    • これをきっかけに Ladybird が ftp URL をサポートするようになるといい
    • Ladybird には現行ブラウザと競争するだけのリソースがない。宣伝はうまくいったが、Chromium に対する利点や存在理由が乏しい
      さらに、証明可能なほど安全ではない C++ で再設計されている点で、大きなセキュリティリスクがある
  • なりすまそうとしているプラットフォームに合わせて TTL 値をそろえるように IP_TTL も設定しているのだろうか?
    そうでなければ、IP 層でもある程度フィンガープリンティングが可能だ。IP 層の TTL 値が 64 未満なら、現代の Windows 上で実行されていないか、デフォルト TTL を変更した現代の Windows だと明らかになる。現代の Windows のパケットのデフォルト TTL は 128 から始まり、他のほとんどのプラットフォームは 64 から始まるためだ
    他のプラットフォームでもインターネット通信に問題はないので、現代の Windows から来た IP パケットは、リモート側では常に 64 以上、おそらく 64 より少し大きい TTL に見えるはずだ。ただし IP 層のフィンガープリンティングは難しいが、不可能ではない

    • 低レベルの TCP/IP スタックへのアクセスを提供しない PaaS/IaaS を使うときだけ難しい。自前でサーバーを運用しているなら、あらゆる TCP/IP 属性のフィンガープリンティングは非常に簡単だ
      https://en.wikipedia.org/wiki/TCP/IP_stack_fingerprinting
    • 受信パケットの TTL 値はネットワーク状態によって変わるのでは? サーバー側でクライアントの元の値を復元できるのか?
    • TTL はなぜ増加ではなく減少するように設計されたのだろう? 一般的には、トラフィックをルーティングする側が、ルーティングするかどうかとその方法を決めると期待しないか?
  • 待って、TLS ハンドシェイクが違って見えるなら、Web ブラウザだと主張しているが実際には Python/PHP スクリプトであるトラフィックを nginx レベルでフィルタリングできるのでは?
    例えば Chrome のユーザーエージェントを使っているが実際のブラウザではない場合だ。悪性ボットトラフィックの大半がこれに該当するだろうから、単にブロックできるならありがたい

    • Cloudflare は複数の TLS ハンドシェイクパラメータのハッシュである JA3/JA4 TLS フィンガープリントを使っている
      仕組みは https://github.com/FoxIO-LLC/ja4/blob/main/technical_details... に詳しく書かれており、Nginx モジュールも提供されている: https://github.com/FoxIO-LLC/ja4-nginx-module
    • 基本的に Cloudflare のようなセキュリティ企業がやっているのはそれで、さらに JavaScript インタプリタ/DOM を確認するJavaScript チャレンジのようなフィンガープリンティングをもっと多く行っている
    • 可能だし、実際にサイトがやっているが、本当にひどい。信頼性が低く、最新 Windows の最新 Chrome を使っていない全員をブロックしてしまう
      今まさに攻撃を受けているのでなければ、TLS フィンガープリントの許可リストを使うべきではない
    • 記事のツールは、まさにそうしたブロックを避けるためのものに見える
  • 素晴らしいツールだが、クライアントがブラウザかどうかは重要であるべきではない。現実にこういうツールが必要になるのは苦々しい

    • 約6か月前、Internet Explorerを要求する政府のオークションサイトに入ったことがある。本当にInternet Explorerで、サイトも稼働中でオークションデータは最新だった
      Chromeにユーザーエージェント拡張を追加してIEに変えて再試行したところ動作し、サイトのすべての機能も問題なかった。だから苦々しくもあり、腹立たしくもあった。おそらくその政府機関は25年前にWebサイトを作り、その後更新していないのだろう
    • 承認済みのソフトウェアを使っている場合に限り、サイトに入れる。それ以外はすべて悪意あるものと見なす。書類を見せてください!
      こういうゲートキーピングも苦々しく感じる。私の理解では、自作のカスタムブラウザやユーザーエージェントは、彼らを説得できるだけの十分な影響力、資金、ユーザー数などが得られるまで、Cloudflare系のサイトでは決して動かないだろう
  • このツールは、レッドチーム作業で小さなbashスクリプトとGNU parallelを組み合わせて使うとなかなか良い
    範囲指定されたアドレス帯の中で、さまざまな理由によりまともなブラウザにしか応答しなかったり、SNI設定が合っていないと応答しなかったりするHTTPSエンドポイントをマッピングする際に役立った。ヘッダー偽装用の-Hのような通常のcurlオプションもそのまま使える

  • 当時のShow HN投稿: https://news.ycombinator.com/item?id=30378562

    • その時点の2022年にはFirefox専用だった
  • こういうものがここに上がるたび、いつも複雑な気持ちになる。一方では、人々の間にまだ多少の反骨心と独立性が残っていると示されるのは良いことだ
    他方では、「自由は不安定」と見なされる他のプロジェクトと同じく、望まない注目を集めると、これに依存している人たちにとって状況がさらに悪くなる可能性もある。ブラウザを書くのは難しく、既存の強者たちはそれをさらに難しくし続けている

    • ブラウザ開発者たちがブラウザのフィンガープリント可能性を望んでいるように聞こえるが、それは異なる人々がそれぞれ異なる実装をする結果、自然に生じることに近い
      これを反骨心の問題とは見ていない。ソフトウェアがフィンガープリント可能になることは、プライバシー保護とソフトウェアの多様性を損なう
  • Webサイトがボットを問題ないと考えれば許可し、嫌ならユーザーエージェントをブロックしていた単純な時代が少し懐かしい

    • 当時のWebサイトは今ほどリソースを消費しなかった。ボットへの否定的な反発は、Web体験への期待が過度に重くなったことから生じた副作用に近いと思う
  • パッチ3つとシェルラッパーだけなら、Danielがコーディングに乗り出してもよさそうだ。個人的には、これは必ずメインラインcurlに入るべきだと思う