
2026/10/29 2:29
Cloudflare Turnstile ソルバーライブラリ(ヘッドレスブラウザ不要)
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
主な要点は、
cfsolve が無頭ブラウザを必要としない Rust ベースのライブラリおよびコマンドラインツールであり、Cloudflare Turnstile の課題を解決することを目的としている点である。仮想ブラウザを起動する代わりに、Safari および Chromium と互換性のある JSON ベースのブラウザプロファイルを活用し、ウィジェットに必要なトークンを生成するか、課題ページに対してクリアランスクッキーを発行する。正常に動作させるためには、ページの URL、サイトキー、生の HTML といった特定の入力を提供し、現在の設定に応じて再試行可能なネットワーク問題から再試行不能なブロックまで幅広いエラー種別を管理する必要がある。このプロジェクトの開発には、Rust、CMake、および完全性を保つためのパッチ済みの BoringSSL 依存関係を含む特定のエビロメントが必要である。さらに、適切な使用には、プロフィールディレクトリが損なわれないように維持し、プロフィールの IP アドレスとユーザーエージェント文字列に正確に一致するクッキーを保ち続けることが求められる。この機能により、開発者は MIT ライセンスの下でパス依存関係を通じて cfsolve を自らのアプリケーションに直接統合でき、広範な採用を可能にするとともに、btls-sys および wreq といった基礎的なコンポーネントに対してカスタマイズされた制御を行い、特化したソリューションを実現できる。本文
cfsolve: Cloudflare Turnstile 解決用 Rust ライブラリ
cfsolve は、ヘッドレスブラウザを使わずに Cloudflare Turnstile ウィジェットや挑戦ページを解決するための Rust ライブラリおよびコマンドラインツール です。
機能と出力
- Turnstile ウィジェットの場合: Turnstile トークンを返し、ログイン処理を完了させます。
- 挑戦ページの場合:
クッキーを返し、保護されたページへのアクセスを可能にします。cf_clearance - 解決方法の違い:
- ウィジェット: ページ URL、sitekey を使用。HTML は不要なケースが多いです。
- 挑戦ページ: ページへの直接アクセスまたはその HTML が必須です。
ブラウザのプロフィール管理
cfsolve は、特定ブラウザを模擬するための プロフィールファイル を利用します(例:
profiles/safari-26-ios.json)。
プロフィールの注意点
- 保存時のルール: コピーする際は、必ずプロフィールとその関連ディレクトリも一緒に移動させてください。プロフィールは挑戦時のブラウザチェックに対する記録された応答を参照しています。
- 生成方法:
- 通常は手動作業または AI を活用する必要があります。
- キャプチャプロキシを設定して実際のブラウザで問題に解決することで、Cloudflare に送信されたデコード済みのペイロードを自動記録し生成をサポートできます。
- 現在サポートされているタイプ:Safari および Chrome (iium) のみです。
コマンドラインツールの使い方
基本コマンド
cargo build --release --bin challenge
実行例
./target/release/challenge \ --page 'https://example.com/login' /tmp/solve \ --solve --fingerprint profiles/safari-26-ios.json
動作仕様:
- 成功時: トークン(または
)を標準出力に、進行状況を標準エラー出力に表示。cf_clearance - ディレクトリ引数 (
): デバッグ用リクエスト・応答を保持するため、空または既存である必要があります。/tmp/solve - デフォルト動作: ページ内の最初のウィジェット解決、または挑戦ページクリア。
- 複数のウィジェットがある場合:
で特定を選択します。--sitekey - サイト固有の設定:
およびaction
も含める必要があります。cData
- 複数のウィジェットがある場合:
Sitekey を指定したケース
特定のサイトキーを指定する場合の例:
./target/release/challenge \ --page 'https://example.com/login' /tmp/solve \ --solve --fingerprint profiles/safari-26-ios.json \ --sitekey 'SITEKEY' --action 'login' --cdata 'CUSTOM_DATA'
空白のページ: Sitekey のみを持つ場合、以下のオプションを追加してください。
--blank-page --page <actual_site_url>
オプション一覧
| オプション | 説明 |
|---|---|
| 使用するブラウザプロフィールファイル。必須。 |
| ウィジェットが存在するページまたは挑戦ページの URL。 |
| 解決を実行します(フラグなしでは送信のみで停止)。 |
| sitekey により対象ウィジェットを選択します。 |
| が必要な場合、アクションデータを上書きします。 |
| ページ読み込みをスキップし、空白ページ上にウィジェットを描画( と 必須)。 |
| プロキシ経由でリクエストを送信 (, , , )。認証情報は URL に埋め込み可。 |
| ヘルプ表示。 |
ライブラリとしての使用法
パッチ適用と依存関係
Cargo.toml に cfsolve を追加する際、トップレベルの [patch] セクションもコピーしてください。これにより Cargo が依存関係のパスを正しく読み取ります。
[dependencies] cfsolve = { path = "/path/to/cfsolve", default-features = false } tokio = { version = "1", features = ["macros", "rt-multi-thread"] } [patch.crates-io] btls-sys = { path = "/path/to/cfsolve/vendor/btls-sys" } wreq = { path = "/path/to/cfsolve/vendor/wreq" } http2 = { path = "/path/to/cfsolve/vendor/http2" }
実装の要点:
を指定することで、内部コマンドツールが無効化され、ソルバー機能のみが動作します。default-features = false- Rust バージョンは
に記載されたもの(またはそれより新しい)を使用してください。rust-toolchain.toml
コード実装例
基本的な解決処理
use cfsolve::{Browser, Options, PageSource, Turnstile}; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // ブラウザインスタンスを読み込んで共有します(一度読み込み推奨) let browser = Browser::read("/path/to/cfsolve/profiles/safari-26-ios.json")?; let options = Options::default(); // ウィジェット解決 let turnstile = Turnstile { url: "https://example.com/login".parse()?, page: PageSource::Navigate, widget: None, }; let token = browser.solve_turnstile(turnstile, &options).await?; println!("{token}"); // 挑戦ページクリア let cleared = browser.clear(&"https://example.com/".parse()?, &options).await?; println!("cf_clearance={}", cleared.clearance); println!("{} cookies; protected page: {}", cleared.cookies.len(), cleared.page.url); Ok(()) }
Sitekey または独自 HTML を持つ Turnistle
URL と sitekey のみの場合、
PageSource::Blank を使用し、Widget オプションを指定します。
use cfsolve::{PageSource, Turnstile, Widget}; let turnstile = Turnstile { url: "https://example.com/login".parse()?, page: PageSource::Blank, widget: Some(Widget { sitekey: "SITEKEY".into(), action: Some("login".into()), cdata: None, }), }; let token = browser.solve_turnstile(turnstile, &options).await?;
設定のポイント:
- Action/CData: サイトが設定する値に従ってください。未設定の場合は
にします。None - 複数のウィジェット:
と共に特定のPageSource::Navigate
を渡して選択可能です。Widget - 読み込んだページ: 既に HTML を持つ場合(例:ログイン画面裏側)、
で URL と HTML を渡します。PageSource::Html
クリアランスのルール
- プロファイルと同じ IP アドレスとユーザーエージェントから
クッキーを送信する必要があります。これ否则 Cloudflare は拒否します。cf_clearance
チャンレンジ(挑戦)ページの処理
明確なケース別処理
- ブラウザがフェッチ:
を使用。返却されたbrowser.clear(&url, &options)
にクッキーと保護ページが含まれます。Clearance- 挑戦が存在しない場合は
で失敗します。Error::NotChallenged - 外部でフェッチしたページは、
を渡して処理可能です。FetchedPage
- 挑戦が存在しない場合は
ユーニバーサル解決 (browser.solve
)
browser.solveURL の種類が不明な場合や両方をカバーしたい場合に使用します:
use cfsolve::Outcome; match browser.solve(&url, &options).await? { Outcome::Token(token) => println!("{token}"), Outcome::Cleared(cleared) => println!("cf_clearance={}", cleared.clearance), }
オプション(プロキシとログ出力)
プロキシ設定
各操作ごとに
Options を介して HTTP、HTTPS、SOCKS5 を設定できます:
let options = cfsolve::Options { proxy: Some("socks5h://127.0.0.1:1080".into()), ..Default::default() };
ログとデバッグ出力(Sink)
ライブラリ操作はデフォルトでサイレントです。進行状況やデバッグファイルを取得するには
Sink を実装し、options.sink に設定してください:
let options = cfsolve::Options { sink: Some(Arc::new(your_sink)), ..Default::default() };
エラーハンドリング
| エラー | 原因 | リトライ推奨? |
|---|---|---|
| 接続失敗 | はい |
| Cloudflare が解決を拒否 | はい |
| サイトがエラーページを返す | いいえ |
| トークン要求に対し、挑戦ページを受け取り | はい(クリア後) |
| 挑戦がない場合の失敗 | いいえ |
| プロフィールまたはオプションが無効 | いいえ |
| 新しい挑戦形式や無効な構造など | いいえ |
ライセンス
- ソースコード:MIT ライセンス。
- 例外:
内のパッチ済み依存関係については、それぞれの元のライセンスが維持されます。vendor/