Subscribe to receive notifications of new posts:

フェッチリクエストへのチャレンジで、TurnstileとCloudflare WAFを統合

12/18/2023

6 min read
Integrating Turnstile with the Cloudflare WAF to challenge fetch requests

2ヶ月前より、Cloudflare Turnstileが一般利用できるようになりました。これは、あらゆるWebサイトのオーナーに、CAPTCHAを発行することなくボットを撃退する簡単な方法を提供します。Turnstileを使えば、Webサイトの所有者であれば誰でも、簡単なコードスニペットで、自分のWebサイトにフラストレーションのないCloudflareチャレンジを埋め込むことができ、確実に人間のトラフィックだけを通過させるようにできます。Webサイトのフロントエンドを保護するだけでなく、TurnstileはWeb管理者がブラウザ起動型(AJAX)API呼び出しを硬化させることもできます。これらのAPIは、React、Angular、Vue.jsで作成されたような動的なシングルページのWebアプリで一般的に使用されています。

嬉しいことに、当社はTurnstileをCloudflare Webアプリファイアウォール(WAF)に統合したことを、本日、発表いたします。これは、Web管理者がTurnstileのコードスニペットをWebサイトに追加し、そのリクエストを管理するためにCloudflare WAFを設定できることを意味します。WAFルールを使用したカスタマイズは自由に行えます。例えば、Turnstileによって認証されたユーザが、それ以上チャレンジに直面することなく、アプリケーションのすべてのAPIエンドポイントとやりとりできるようにすることもできますし、Loginのような特定の機密エンドポイントが常にチャレンジを発行するように設定することもできます。

Cloudflare WAFでフェッチリクエストにチャレンジを実施

CloudflareのWAFによって保護されている何百万ものWebサイトは、JSチャレンジ、Managed Challenge、インタラクティブチャレンジを活用してボットを阻止し、人間を通過させています。これらのチャレンジのそれぞれについて、Cloudflareはマッチするリクエストを傍受し、ユーザーが人間であることを証明するための基本的なタスクを完了すると、ブラウザによってレンダリングされたHTMLページで応答します。ユーザーがチャレンジに成功すると、ユーザーはcf_clearance cookieを受け取ります。このクリアランスCookieは、ユーザーがチャレンジに成功したことやチャレンジの種類、いつ完了したかをCloudflareに伝えます。クリアランスCookieはユーザー間で共有することはできず、Cloudflareのお客様がセキュリティ設定ダッシュボードで設定した時間のみ有効です。

このプロセスは、ブラウザがフェッチリクエストでチャレンジを受信し、ブラウザが以前にチャレンジを通過していない場合を除き、うまく機能します。フェッチリクエスト、またはXML HTTPリクエスト(XHR)では、ブラウザは単純なテキスト(JSON または XML形式)を返すことを期待し、チャレンジを実行するために必要なHTMLをレンダリングすることはできません。

例として、ピザ屋のオーナーを想像してみましょう。このオーナーはReactでオンライン注文フォームを構築し、支払いを処理するAPIエンドポイントにデータを送信する決済ページを持っています。ユーザーがクレジットカードの詳細を追加するためにWebフォームを表示すると、Managed Challengeをパスすることができますが、ユーザーがフェッチリクエストでクレジットカードの詳細を送信すると、ブラウザはチャレンジの実行に必要なコードを実行しません。ピザ屋のオーナーにとって、疑わしい(しかし正当な可能性のある)リクエストを処理する唯一の選択肢は、それをブロックすることですが、誤検出のリスクもあり、レストランが販売機会を失う原因となりかねません。

そこでTurnstileが役に立ちます。Turnstileを使えば、インターネット上の誰もが自分のWebサイトのどこにでもCloudflareチャレンジを埋め込むことができます。今日まで、Turnstileの出力は1回限りのトークンのみでした。Turnstileは、お客様がこれらのフェッチリクエストに対してチャレンジを発行できるように、埋め込んだドメインのクリアランスCookieを発行できるようになりました。お客様は、フェッチリクエストの前にHTMLページ内でチャレンジを発行し、Web訪問者が決済APIと対話することを事前に許可することができます。

Turnstile Pre-Clearanceモード

ピザ屋の例に戻ると、TurnstileをCloudflare WAFと統合するためにPre-Clearanceを使用する3つの大きな利点があります。

  1. ユーザーエクスペリエンスの向上。Turnstileの埋め込みチャレンジは、Web訪問者が支払いの詳細を入力している間、バックグラウンドで実行することができます。
  2. エッジでより多くのリクエストをブロック。Turnstileは、それが埋め込まれているドメインのクリアランスCookieを発行するようになったため、ピザ屋のオーナーはカスタムルールを使用して、決済APIへのすべてのリクエストに対してManaged Challengeを発行することができます。これにより、決済APIを直接狙おうとする自動化された攻撃は、APIに到達する前にCloudflareによって阻止されます。
  3. (オプション)アクションとユーザを保護します。Pre-Clearanceのメリットを得るためにバックエンドのコードを変更する必要はありません。しかし、Turnstileをさらに統合することで、統合されたAPIのセキュリティが向上します。ピザ屋のオーナーは、受信したTurnstileトークンを検証するために決済フォームを調整することができ、すべての支払いの試みがセッションハイジャックから決済エンドポイントを保護するためにTurnstileによって個別に検証されるようにできます。

Pre-Clearanceを有効にしたTurnstileウィジェットでも、Turnstileトークンは発行されます。このため、エンドポイントへのリクエストごとにセキュリティチェックが必要なほど重要なエンドポイントか、またはチェックはセッションに1回だけ必要かを柔軟に判断することができます。Turnstileウィジェットによって発行されたクリアランスCookiesは、設定の必要なく、Turnstileウィジェットが埋め込まれているCloudflareゾーンに自動的に適用されます。トークンが有効なクリアランスタイムは、ゾーン固有の「チャレンジ通過」タイムによって管理されます。

Pre-ClearanceによるTurnstileの導入

基本的な実装を通して、これを具体的に行っていきましょう。始める前に、/your-apiエンドポイント上でフロントエンドとバックエンドのやり取りをエミュレートする簡単なデモアプリをセットアップしました。

そのために、次のようなコードを用意しました。

<!DOCTYPE html>
<html lang="en">
<head>
   <title>Turnstile Pre-Clearance Demo </title>
</head>
<body>
  <main class="pre-clearance-demo">
    <h2>Pre-clearance Demo</h2>
    <button id="fetchBtn">Fetch Data</button>
    <div id="response"></div>
</main>


<script>
  const button = document.getElementById('fetchBtn');
  const responseDiv = document.getElementById('response');
  button.addEventListener('click', async () => {
  try {
    let result = await fetch('/your-api');
    if (result.ok) {
      let data = await result.json();
      responseDiv.textContent = JSON.stringify(data);
    } else {
      responseDiv.textContent = 'Error fetching data';
    }
  } catch (error) {
    responseDiv.textContent = 'Network error';
  }
});
</script>

ボタンを作成しました。クリックすると、Cloudflareは/your-apiエンドポイントにfetch()リクエストを行い、結果をレスポンスコンテナに表示します。

ここで、/your-apiエンドポイントをManaged Challengeで保護するCloudflare WAFルールが設定されていると考えてみましょう。

このルールのため、先ほど書いたアプリは前述の理由で失敗することになります(ブラウザはJSONレスポンスを期待していますが、代わりにHTMLとしてチャレンジページを受け取ります)。

Networkタブを見ると、/your-apiへのリクエストに403応答が返されていることがわかります。

検査すると、Cf-Mitigatedヘッダーは、Web訪問者が以前にチャレンジを解決していないため、Cloudflareのファイアウォールによって応答がチャレンジされたことを示しています。

私たちのアプリでこの問題に対処するために、使用したいTurnstile sitekeyのPre-ClearanceモードでTurnstileウィジェットを設定します。

アプリでは、Cf-Mitigated応答が受信されると、Turnstileを呼び出すためにfetch()関数をオーバーライドします。

<script>
turnstileLoad = function () {
  // Save a reference to the original fetch function
  const originalFetch = window.fetch;

  // A simple modal to contain Cloudflare Turnstile
  const overlay = document.createElement('div');
  overlay.style.position = 'fixed';
  overlay.style.top = '0';
  overlay.style.left = '0';
  overlay.style.right = '0';
  overlay.style.bottom = '0';
  overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
  overlay.style.border = '1px solid grey';
  overlay.style.zIndex = '10000';
  overlay.style.display = 'none';
  overlay.innerHTML =       '<p style="color: white; text-align: center; margin-top: 50vh;">One more step before you proceed...</p><div style=”display: flex; flex-wrap: nowrap; align-items: center; justify-content: center;” id="turnstile_widget"></div>';
  document.body.appendChild(overlay);

  // Override the native fetch function
  window.fetch = async function (...args) {
      let response = await originalFetch(...args);

      // If the original request was challenged...
      if (response.headers.has('cf-mitigated') && response.headers.get('cf-mitigated') === 'challenge') {
          // The request has been challenged...
          overlay.style.display = 'block';

          await new Promise((resolve, reject) => {
              turnstile.render('#turnstile_widget', {
                  'sitekey': ‘YOUR_TURNSTILE_SITEKEY',
                  'error-callback': function (e) {
                      overlay.style.display = 'none';
                      reject(e);
                  },
                  'callback': function (token, preClearanceObtained) {
                      if (preClearanceObtained) {
                          // The visitor successfully solved the challenge on the page. 
                          overlay.style.display = 'none';
                          resolve();
                      } else {
                          reject(new Error('Unable to obtain pre-clearance'));
                      }
                  },
              });
          });

          // Replay the original fetch request, this time it will have the cf_clearance Cookie
          response = await originalFetch(...args);
      }
      return response;
  };
};
</script>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=turnstileLoad" async defer></script>

上のスニペットでは、たくさんのことが行われています。まず、非表示のオーバーレイ要素を作成し、ブラウザのfetch()関数をオーバーライドします。fetch()関数は、Cf-Mitigatedヘッダーの「チャレンジ」を見直すように変更されます。チャレンジが発行された場合、最初の結果は失敗します。代わりに、Turnstileオーバーレイ(Pre-Clearanceが有効)がWebアプリケーションに表示されます。Turnstileチャレンジが完了すると、Turnstileがcf_clearance Cookieを取得した後に、前のリクエストを再試行し、Cloudflare WAFを通過させます。

Turnstileウィジェットを解決すると、オーバーレイが消え、要求されたAPIの結果が正常に表示されます。

Pre-Clearanceは、Cloudflareのすべてのお客様にご利用いただけます

無料プラン以上のCloudflareユーザーは、リクエスト数無制限でマネージドモードのTurnstileを無料で使用できます。重要なAPIエンドポイントのセキュリティとユーザーエクスペリエンスの向上をお考えのCloudflareユーザーの方は、今すぐダッシュボードにアクセスして、Pre-Clearance付きのTurnstileウィジェットを作成してください。

theNET
We protect entire corporate networks, help customers build Internet-scale applications efficiently, accelerate any website or Internet application, ward off DDoS attacks, keep hackers at bay, and can help you on your journey to Zero Trust.

Visit 1.1.1.1 from any device to get started with our free app that makes your Internet faster and safer.

To learn more about our mission to help build a better Internet, start here. If you're looking for a new career direction, check out our open positions.
Security (JP)CAPTCHA (JP)Bots (JP)Turnstile (JP)Product News (JP)Developers (JP)Micro-frontends (JP)日本語

Follow on X

Adam Martinetti|@adamemcf
Benedikt Wolters|@worengawins
Miguel de Moura|@miguel_demoura
Cloudflare|@cloudflare

Related posts

April 12, 2024 1:00 PM

Cloudflareのお客様がLet's Encryptの証明書チェーンの変更の影響を受けないようにする方法

Let's Encryptのクロス署名チェーンは9月に有効期限が切れます。この影響は、古いトラストストアを使用するレガシーデバイス(Androidバージョン7.1.1以前)に生じます。この変更による影響がお客様に及ぶことを防ぐため、CloudflareはLet's Encrypt証明書の更新時に別のCAを使用するように移行します...

March 08, 2024 2:05 PM

Log Explorer:サードパーティのストレージを使用せずにセキュリティイベントを監視します

Security AnalyticsとLog Explorerを組み合わせることで、セキュリティチームはCloudflare内でネイティブにセキュリティ攻撃を分析、調査、監視でき、サードパーティのSIEMにログを転送する必要がなくなるため、解決までの時間を短縮し、お客様の総所有コストを削減できます...

March 05, 2024 2:02 PM

セキュリティセンター内の保護されていないアセットを保護:最高情報セキュリティ責任者(CISO)のためのクイックビュー

本日、共通の課題であるインフラストラクチャ全体への包括的な展開を確実に行うために、セキュリティーセンター内に新しい機能セットを導入することを嬉しく思います。セキュリティ体勢を最適化する場所と方法を正確に把握することができます...