🐒

Cloudflare - Bot JavaScript detections の利用法

2025/01/13に公開

Bot JavaScript detectins とは

JavaScript detections are another method that help Cloudflare identify bot requests.

Cloudflare の各 Bot プロダクト は受信した HTTP リクエストの特徴などから受動的に Bot らしさ(Bot Score)を算出し、 Bot からの保護に利用します。一方 JavaScript detections は Cloudflare からクライアントに検知用のスクリプトを渡しその結果を利用するという、能動的な働きかけを追加することで、検知を強化します。

These detections are implemented via a lightweight, invisible JavaScript code snippet that follows Cloudflare’s privacy standards ↗. JavaScript is injected only in response to requests for HTML pages or page views, excluding AJAX calls. API and mobile app traffic is unaffected. Additionally, code is not injected again until the current session expires. After page load, the script is deferred and utilizes a separate thread (where available) to ensure that performance impact is minimal.

The snippets of JavaScript will contain a source pointing to the challenge platform, with paths that start with /cdn-cgi/challenge-platform/.

プラン

Free プランでは Bot Fight Mode と同時に有効となり、有償プランでは有効・無効を設定できます

プラン Bots JavaScript detections
Free Bot Fight Mode 常に有効
Pro, Business, Enterprise Super Bot Fight Mode 有効・無効の切り替え可能
Enterprise Bot Management 有効・無効の切り替え可能

Challenge Platform

JavaScript detections は WAF などでも利用される Challenge Platform の力を借ります。
ただ WAF アクションのチャレンジとは用途が異なり、JavaScript detections 自体がリクエストをブロックすることはありません。

プロダクト 機能 用途 cf_clearance cookie の発行 Challenge Platform との通信
Bot Management JavaScript detections ・Bot Score の補正
(検知 ➜ Score 1)
・検知結果を WAF、Workers などで利用(*)
自ホスト/cdn-cgi/challenge-platform/...
WAF Managed Challenge Challenge(Interactive、Non-Interactive など)に失敗したクライアントをブロック 自ホスト/cdn-cgi/challenge-platform/...

challenges.cloudflare.com/...
WAF JS Challnege Challenge(Non-Interactive)に失敗したクライアントをブロック 自ホスト/cdn-cgi/challenge-platform/...

challenges.cloudflare.com...
WAF Interactive Challenge Challenge(Interactive)に失敗したクライアントをブロック 自ホスト/cdn-cgi/challenge-platform/...

challenges.cloudflare.com/...

(*) JavaScript detections の検知結果(Boolean)は

に格納されます。
PASSED の場合 true、FAILEDMISSING の場合 false となります。

JavaScript detections 検知の確認

Security > Events で検知結果を確認することができます。
下記のような例になります。

  1. JavaScript Verification は Failure 、Bot source JavaScript detections により Bot score は 1

  2. JavaScript Verification は Passed 、Bot source Machine learning により Bot score は 99

Firewall イベントログでも確認可能

firewall_events

$ rclone cat r2:logs/firewall/...log.gz | jq '.Metadata.js_detection'
"PASSED"
"MISSING"

WAF Custom Rules での利用

WAF Custom Rules は下記の 2 つで JavaScript detections の結果を活用することができます。

  1. (Bot 検知で補正された)Bot Score 1
  2. cf.bot_management.js_detection.passed の Boolean

ここでは 2 を試しますが、前提条件は下記の通りです。

条件 テスト環境
You must have JavaScript detections enabled on your zone. ゾーンに JavaScript detections を設定
現時点ではゾーン全体で有効。
You must have updated your Content Security Policy headers for JavaScript detections. 今回オリジンで CSP 利用中のため script-srcnonce を指定
JavaScript detections はその nonce でオリジナルコンテンツにインラインのスクリプト挿入。
同様に self も追加し /cdn-cgi/challenge-platform/... パスを許可。
You must not run this field on websocket endpoints. cf.bot_management.js_detection.passed フィールドを適用する URL は websocket のエンドポイントではない。
You must use the field in a custom rules expression that expects only browser traffic. cf.bot_management.js_detection.passed フィールドを適用する URL はブラウザーからのトラフィックを想定したエンドポイント。
The action should always be a managed challenge in case a legitimate user has not received the challenge for network or browser reasons. アクションは Managed Challenge に設定。
The path specified in the rule builder should never be the first HTML page a user visits when browsing your site. 親ページ /(HTML)を踏んでから対象の /jsd.php(コンテンツタイプ任意)にアクセスを想定。

保護対象のエンドポイントに対する Custom Rules 設定は下記のようになりました。

デモ

親ページへのアクセス

まず親ページ / にリクエストを送ると、下記のようなシーケンスになります。

1️⃣ブラウザーは HTML ボディに埋め込まれた下記のようなスクリプトを見ることになります。

2️⃣ブラウザーが検証に成功し cf_clearance cookie を得ます。ドメインはゾーン自体となっています。

JavaScript detection での cf_clearance cookie の有効期間

JavaScript detections で発行された cf_clearance cookie が有効なあいだは検知が発動されることはありません。
Dev Docs にある Additionally, code is not injected again until the current session expires. の部分については、JavaScript detections の場合、cf_clearance cookie 発行から 12 分程度すると再度 JavaScript detections が実施、cookie が更新される挙動が見れました。(cookie 自体の expire は 1 年)

保護されたエンドポイントへのリクエスト

この状態から WAF Custom Rules で保護された /jsd.php にアクセスします。

3️⃣ 後続の /jsd.php へのリクエストはJavaScript detections を通過した cf_clearance cookie を伴ったリクエストになります。そのため cf.bot_management.js_detection.passed が true となり、Managed Challenge および JavaScript detections を受けることなく、オリジンに到達します。

4️⃣ オリジンからのレスポンスが HTML であっても JavaScript は埋め込まれません。

直接のアクセス

上記の cf_clearance cookie がなく、直接アクセスした場合を想定します。

Managed Challenge

前提条件に記載の The action should always be a managed challenge in case a legitimate user has not received the challenge for network or browser reasons. に従っているので Managed Challenge が発動します。

Managed Challenge を突破すると WAF で cf_clearance cookie が発行されました。

コンテンツが HTML の場合は Managed Challenge 突破の後 JavaScript detections が実施され、成功により JavaScript detections の cf_clearance cookie で上書きされました。
下記のような Challenge Platform が 2 度利用されるシーケンスで、複雑になりました。

Block

試しにアクションを Block にし、HTML のブロックページを利用してみました。

興味深いことにブロックページの HTML に対して JavaScript detections が発動しました。

つまり、ブラウザーは下記のようなブロックページの表示の過程で JavaScript detections をパスし、親ページにアクセスした場合と同じ状況となりました。

読み直すと、JavaScript detections されることなく、応答が返ります。

この挙動はデフォルトブロックページ、 Custom Pages 、どちらも同じでした。

また Custom HTML も同様でした。
ただ、こちらを使うと、親ページにリダイレクトしつつ、JavaScript detections を実施することができたので、Managed Challenge よりユーザーの見た目には優しかったです。

Custom HTML 例
<!doctype html><html><head>
<meta charset="utf-8" />
<meta http-equiv="refresh" content="1; url='https://<parent page>/'"/>
</head>
<body></body></html>

このように自動的に親ページが表示されたため、エンドポイントのリンクをたどることができました。

オリジンサーバーへの JavaScript detections 結果の伝達

JavaScript detections の結果をオリジンサーバーに伝達できるかを確認しました。

Transform Rules の Managed Transformsbot protection headers がありましたが、残念ながら執筆時点で JavaScript detections は含まれていないようです。

そのため Workers(今回は Snippets)でヘッダーに埋め込み伝達しました。

snippets
export default {
    async fetch(request) {
        const newRequest = new Request(request)
        const jsDetectionValue = request.cf?.botManagement?.jsDetection?.passed ?? 'unknown'
        newRequest.headers.set(
            'X-Bot-JS-Detection-Passed',
            jsDetectionValue.toString()
        )
        return fetch(newRequest)
    }
}

オリジン側でも Bot Score や JA4 Fingerprint など他のシグナルと合わせ、セキュリティのロジックの実装に利用できそうです。

さいごに

Bot 検知や WAF のチャレンジあたりは、かいくぐる方法が常に研究され進化し、公開されているものも新旧含めあります。一方、防御プラットフォーム側も継続開発がされており、イタチごっこが続きます。
日進月歩のため、本記事はあくまで執筆時点(2025年1月)の観測情報ということで、メモしておきます。

Discussion