Cloudflare Turnstileの内部構造と回避手法:JA4・cf_clearance・Bot Managementの技術的深掘り

Cloudflare Turnstileの内部構造を技術的に解説。JA4 TLSフィンガープリント、HTTP/2 SETTINGS、ブラウザプローブ、IPレピュテーションの4信号による信頼スコア計算と、住宅プロキシのスティッキーセッションを使った合法的な自動化アプローチをPython実例付きで紹介。

Cloudflare Turnstile Internals: How the 2026 Trust Score Works and How Legitimate Automation Passes

Cloudflare Turnstileの内部構造を理解することは、2026年のウェブスクレイピングや自動化において不可欠です。Turnstileは単なるCAPTCHAの代替品ではなく、ブラウザのTLSフィンガープリント、HTTP/2設定、JavaScript実行環境、IPレピュテーションを組み合わせた多層防御システムです。本記事では、Cloudflare Turnstileの内部構造を技術的に深掘りし、managed-challenge JavaScript、proof-of-work、ブラウザAPIプローブ、そしてcf_clearance cookieの発行メカニズムを解説します。認可された自動化においてウェブスクレイピングを行うエンジニアにとって、これらの知識は必須です。

法的注意事項: 本記事の内容は、認可されたセキュリティ研究、公開データへのアクセス、正当な自動化を目的としています。Computer Fraud and Abuse Act (CFAA) や GDPR の範囲内で、対象サイトの利用規約と robots.txt を遵守してください。資格情報の悪用や不正アクセスを助長するものではありません。

Cloudflare Turnstileの内部構造とは

Turnstileは Cloudflare の Bot Management プラットフォームの一部として機能し、従来の CAPTCHA(画像選択など)を置き換える「マネージドチャレンジ」を提供します。ユーザーには「確認中...」という短いメッセージが表示されるだけですが、裏側では複数の検証レイヤーが同時に実行されています。Turnstileの公式ドキュメントでは、このプロセスを「non-interactive challenge」と呼んでいます(Cloudflare Turnstile公式ドキュメント参照)。

Turnstileの動作フローは以下の通りです:

  1. 初期ロード: ページに埋め込まれた Turnstileウィジェット(cf-turnstile div)が Cloudflare のチャレンジJavaScriptを読み込みます。
  2. ブラウザプローブ: JavaScript が navigator.userAgentnavigator.platformscreen.width/heightcanvas.toDataURL()WebGLRenderingContext.getParameter()AudioContext などのAPIを呼び出し、ブラウザ環境の整合性を検証します。
  3. Proof-of-Work: クライアント側で軽量な計算パズル(ハッシュ探索)を実行し、自動化ツールに一定の計算コストを課します。
  4. 信号送信: 収集した信号が Cloudflare エッジに送信され、信頼スコアが計算されます。
  5. cf_clearance 発行: スコアが閾値を超えると、cf_clearance cookie が発行され、以降のリクエストでチャレンジがスキップされます。

このプロセスは通常 1〜3秒で完了しますが、検証に失敗した場合は対話型チャレンジ(画像選択など)にフォールバックします。

Turnstileが実行する managed-challenge JavaScript と proof-of-work

managed-challenge JavaScript

Turnstileの JavaScript は難読化されており、実行時に動的にコードを生成します。主要な検証項目には以下が含まれます:

  • navigator プロパティの整合性: navigator.webdrivertrue でないか、navigator.languages が空でないか、navigator.plugins の数が合理的か
  • Canvas フィンガープリント: 特定の文字列を描画したキャンバスの toDataURL() ハッシュを計算し、GPU/ドライバーの特徴を一意に識別
  • WebGL プローブ: WEBGL_debug_renderer_info 拡張から UNMASKED_VENDOR_WEBGLUNMASKED_RENDERER_WEBGL を取得し、GPUモデルを特定
  • AudioContext フィンガープリント: OfflineAudioContext で特定の波形を生成し、DSP処理の浮動小数点誤差からデバイスを一意に識別

これらの信号は組み合わされて「ブラウザフィンガープリント」を構成し、ヘッドレスブラウザや自動化ツールを検出します。MDN Web Docsで WebGL API の詳細を確認できます。

Proof-of-Work

Turnstile の proof-of-work は、SHA-256 ベースの軽量なハッシュ探索です。サーバーから difficulty パラメーターと nonce が送信され、クライアントは SHA256(challenge + nonce + counter) が特定のビット数の先行ゼロを持つまで counter をインクリメントします。通常、difficulty は 4〜6ビット程度に設定され、リアルタイムブラウザでは 200〜500ms で完了しますが、ヘッドレス環境では JavaScript エンジンの最適化差異によって実行時間が異常になる場合があります。

4つの信号による信頼スコア — JA4、HTTP/2、ブラウザフィンガープリント、IP

Cloudflare の Bot Management は、4つの主要信号を組み合わせて信頼スコアを計算します。これらの信号は、Cloudflare Turnstileバイパスを試みる際にすべて考慮する必要があります。

1. JA4 TLS フィンガープリント

JA4 は FoxIO によって開発された TLS クライアントフィンガープリント手法で、TLS ClientHello メッセージの構造をハッシュ化します。従来の JA3 との重要な違いは、拡張機能(extensions)をソートしてからハッシュを計算する 点です。これにより、拡張機能の順序が異なる同一クライアントでも同じハッシュ値が得られます(JA4 GitHub リポジトリ参照)。

JA4 のフォーマットは a_b_c_d の4セグメント構造です:

  • a: TLSバージョンとSNI有無(例: t13d = TLS 1.3 + SNIあり)
  • b: 拡張機能数と暗号スイート数
  • c: 拡張機能のソート済みリスト
  • d: 暗号スイートのリスト

Chrome の JA4 と Python requests ライブラリの JA4 は完全に異なります。例えば、Chrome 120 の JA4 は t13d1516h2_8daaf6152771_b0da82dd1658 のような値になりますが、Python urllib3 のデフォルト TLS スタックは OpenSSL ベースの異なる拡張機能セットを提示します。Cloudflare Bot Management は JA4 を信頼スコアの主要な信号として使用します。

2. HTTP/2 SETTINGS フレーム

HTTP/2 接続の SETTINGS フレームには、クライアント固有のパラメーターが含まれます:

パラメーターChrome の典型値Python httpx の典型値
HEADER_TABLE_SIZE655364096
ENABLE_PUSH00
INITIAL_WINDOW_SIZE62914564194304
MAX_HEADER_LIST_SIZE262144(未設定)

これらの値の組み合わせはクライアント実装ごとに固有であり、Cloudflare はこのパターンを追加の信号として使用します。

3. ブラウザフィンガープリント

前述の Canvas、WebGL、AudioContext に加えて、以下の信号も収集されます:

  • フォント列挙: 利用可能なフォントリストのハッシュ
  • 画面解像度と色深度: screen.width × screen.height × screen.colorDepth
  • タイムゾーン: Intl.DateTimeFormat().resolvedOptions().timeZone
  • WebRTC ICE候補: ローカルIPアドレスの漏洩検出

4. IP レピュテーション

Cloudflare は IP アドレスを複数のカテゴリーに分類します:

  • データセンター IP: AWS、GCP、Azure などのクラウドプロバイダー IP 範囲。信頼スコアが低い。
  • 住宅 IP: ISP から一般ユーザーに割り当てられた IP。信頼スコアが高い。
  • モバイル IP: 携帯キャリアの IP 範囲。中〜高信頼スコア。
  • 既知のプロキシ/VPN IP: 公開プロキシリストや VPN プロバイダーの IP 範囲。信頼スコアが低い。

なぜ Python の JA4 が Chrome の主張で即座に検出されるのか

自動化ツールが最も犯しやすい間違いは、HTTP ヘッダーで User-Agent: Mozilla/5.0 ... Chrome/120 ... を主張しながら、TLS レイヤーで Python/OpenSSL の JA4 を提示することです。

Cloudflare の Bot Management は、この矛盾を 1 ミリ秒未満で検出します。仕組みは単純です:

  1. TLS ClientHello を解析し、JA4 ハッシュを計算
  2. JA4 ハッシュを既知のブラウザファミリーデータベースと照合
  3. HTTP ヘッダーの User-Agent と JA4 の一貫性を検証
  4. 不一致の場合、信頼スコアを即座に低下

例えば、User-Agent が Chrome 120 を主張しているのに、JA4 が t13d1716h2_...(Chrome のパターン)ではなく t13d1614h2_...(OpenSSL のパターン)を提示した場合、Cloudflare は即座にマネージドチャレンジをトリガーします。

これは curl-impersonatetls-client のような TLS 模倣ライブラリが存在する理由です。これらは Chrome と同じ TLS 拡張機能、暗号スイート、HTTP/2 SETTINGS を提示するように設計されています。しかし、TLS レイヤーを模倣しても、JavaScript 実行環境の模倣は別の課題です。

cf_clearance cookie の IP 固定と住宅プロキシの重要性

cf_clearance cookie は、Turnstile チャレンジに合格した証明として発行されますが、この cookie は IP アドレスと User-Agent に厳密にバインド されています。

具体的には:

  • cf_clearance 発行時の IP アドレスとリクエスト時の IP アドレスが異なる場合、cookie は無効化されます
  • cf_clearance 発行時の User-Agent とリクエスト時の User-Agent が異なる場合も無効化されます
  • cf_clearance の有効期限は通常 30分〜2時間です(サイトの設定による)

これが住宅プロキシが重要な理由です。データセンタープロキシの IP は低い信頼スコアを受けるため、チャレンジ自体がトリガーされる可能性が高くなります。一方、住宅プロキシの IP は高信頼スコアを受けるため、チャレンジがスキップされるか、軽度の検証で済みます。

さらに、cf_clearance を取得した後、同じ IP アドレスでリクエストを継続する必要があるため、スティッキーセッション(同一の出口IPを維持するプロキシセッション)が不可欠です。

ProxyHat を使った実践的アプローチ

以下は、ProxyHat の住宅プロキシとスティッキーセッションを使用して、Cloudflare Turnstile で保護されたページに正当にアクセスするアプローチです。設定の詳細については ProxyHat ドキュメントを参照してください。

ステップ 1: スティッキーセッションの作成

ProxyHat のスティッキーセッションは、ユーザー名に -session- フラグを追加することで有効になります:

curl -x http://user-session-turnstile01:pass@gate.proxyhat.com:8080 \
  https://example.com

この設定により、turnstile01 というセッションIDに固定された住宅IPが割り当てられ、セッションが維持されている間は同じ出口IPが使用されます。

ステップ 2: 実ブラウザでの cf_clearance 取得

Playwright を使用して、実際のブラウザで Turnstile チャレンジを完了し、cf_clearance cookie を取得します:

from playwright.sync_api import sync_playwright

PROXY_URL = "http://user-session-turnstile01:pass@gate.proxyhat.com:8080"

with sync_playwright() as p:
    browser = p.chromium.launch(
        headless=False,
        proxy={"server": PROXY_URL}
    )
    context = browser.new_context(
        user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                   "AppleWebKit/537.36 (KHTML, like Gecko) "
                   "Chrome/120.0.0.0 Safari/537.36"
    )
    page = context.new_page()
    page.goto("https://example.com")

    # Turnstile が自動的に完了するのを待つ
    page.wait_for_timeout(5000)

    # cf_clearance cookie を取得
    cookies = context.cookies()
    cf_clearance = next(
        (c for c in cookies if c["name"] == "cf_clearance"),
        None
    )

    if cf_clearance:
        print(f"cf_clearance: {cf_clearance['value']}")
        print(f"User-Agent: {context.user_agent}")

    browser.close()

ステップ 3: cf_clearance を使った後続リクエスト

取得した cf_clearance と User-Agent を、同じセッションIDのプロキシ経由で使用します:

import requests

PROXIES = {
    "http": "http://user-session-turnstile01:pass@gate.proxyhat.com:8080",
    "https": "http://user-session-turnstile01:pass@gate.proxyhat.com:8080",
}

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/120.0.0.0 Safari/537.36",
    "Cookie": f"cf_clearance={cf_clearance_value}",
}

response = requests.get("https://example.com/data",
                        proxies=PROXIES,
                        headers=HEADERS)
print(response.status_code)

重要: user-session-turnstile01 は同じセッションIDを使用し続ける必要があります。セッションIDが変わると、異なる出口IPが割り当てられ、cf_clearance が無効化されます。

地理的ターゲティング

特定の国からのアクセスが必要な場合は、ユーザー名に国コードを追加できます:

curl -x http://user-country-US-session-turnstile01:pass@gate.proxyhat.com:8080 \
  https://example.com

これにより、米国の住宅IPが割り当てられ、地理的に一貫したセッションが維持されます。利用可能なロケーションについては当社のロケーションページを参照してください。

適切な利用場面と法的考慮事項

適切な利用場面

  • 公開データへのアクセス: 検索結果、公開価格情報、公開統計データの収集。SERPトラッキングも参照。
  • 認可されたセキュリティ研究: 自社インフラや依頼された対象のペネトレーションテスト
  • 正当な競合調査: 公開されている価格や製品情報の監視
  • QA自動化: 自社ウェブサイトの機能テスト

不適切な利用場面

  • 他者のアカウントへの不正アクセス
  • クレデンシャルスタッフィング攻撃
  • 対象サイトの利用規約で明示的に禁止されているスクレイピング
  • 個人情報の無断収集(GDPR違反)

米国の Computer Fraud and Abuse Act (CFAA) は、認可されていないアクセスを犯罪とみなす可能性があります。2022年の Van Buren v. United States 判決以降、「認可」の解釈は限定的になりましたが、利用規約違反が常に安全とは限りません。詳細は Wikipedia: CFAA を参照してください。

また、EU の GDPR に基づくデータ保護要件も考慮する必要があります。個人情報を含むデータの収集・処理には、適切な法的根拠が必要です。

よくある間違いとエッジケース

間違い 1: User-Agent の不一致

cf_clearance を取得したブラウザの User-Agent と、後続の requests ライブラリの User-Agent が異なると、cookie が無効化されます。常に同一の User-Agent を使用してください。

間違い 2: プロキシセッションの変更

セッションIDを変更すると、新しい出口IPが割り当てられ、cf_clearance が無効化されます。長時間のスクレイピングタスクでは、同じセッションIDを維持してください。ProxyHat のスティッキーセッションは長時間維持できます。

間違い 3: HTTP/2 の模倣不足

requests ライブラリは HTTP/1.1 を使用しますが、Chrome は HTTP/2 を使用します。Cloudflare は HTTP バージョンも信号として使用するため、可能な限り HTTP/2 をサポートするライブラリ(httpx など)を使用してください。

間違い 4: データセンタープロキシの使用

データセンタープロキシの IP 範囲は Cloudflare のレピュテーションシステムで低く評価されます。ウェブスクレイピングにおいては、住宅プロキシの使用を強くお勧めします。

エッジケース: cf_clearance の期限切れ

cf_clearance の有効期限は通常 30分〜2時間です。期限切れ後は、再度チャレンジを完了する必要があります。長時間実行するジョブでは、cf_clearance の有効期限を監視し、期限が近づいたら再取得する仕組みを実装してください。

プロキシタイプの比較

特徴住宅プロキシデータセンタープロキシモバイルプロキシ
IPレピュテーション中〜高
cf_clearance 取得成功率85〜95%10〜30%70〜85%
スティッキーセッション対応対応対応
速度中(50〜200ms)高(10〜50ms)低〜中(100〜300ms)
価格中〜高

ProxyHat の料金プランでは、住宅プロキシ、データセンタープロキシ、モバイルプロキシを提供しています。Cloudflare Turnstile を通過する必要がある場合は、住宅プロキシの選択を強くお勧めします。

Key Takeaways

重要なポイント

  • Cloudflare Turnstile は TLS(JA4)、HTTP/2 SETTINGS、ブラウザフィンガープリント、IP レピュテーションの4信号で信頼スコアを計算する
  • cf_clearance cookie は IP と User-Agent に厳密にバインドされるため、スティッキーセッションが必須
  • 住宅プロキシは高い IP レピュテーションを提供し、チャレンジのトリガーを最小限に抑える
  • 実ブラウザで cf_clearance を取得し、同じセッションIDで後続リクエストを送信するのが最も確実なアプローチ
  • すべての自動化は対象サイトの利用規約と適用法令(CFAA、GDPR)を遵守すること

Cloudflare Turnstileの内部構造を理解し、適切なプロキシインフラを構築することで、正当な自動化タスクを高い成功率で実行できます。ProxyHat の住宅プロキシとスティッキーセッションを活用し、実ブラウザで cf_clearance を取得・再利用するアプローチは、2026年のウェブスクレイピングにおいて最も堅牢な手法の一つです。

始める準備はできましたか?

AIフィルタリングで148か国以上、5,000万以上のレジデンシャルIPにアクセス。

料金を見るレジデンシャルプロキシ
← ブログに戻る