こんにちは、公文に通っている娘が先日「公文でお友達とおしゃべりしちゃうのが良くないから、今日は皆で離れた席に座るようにしてみた!」と言っていて、「おしゃべりしないように気をつける」ではなくちゃんと仕組みで解決したことに感心した木村です。
この記事はオルターブース2025年のアドベントカレンダーの16日目の記事です。前日はマイクロソフトTop Partner EngineerのはっしーによるGHAS + Defenderのお話でした。
また、15日目はみっつーのGitHub Copilot の自動モデル選択の記事も投稿されています。こちらはInfocomアドベントカレンダーの時期になっています。
気がつけば弊社もメンバーが25人を超えて、1つのアドベントカレンダーでは全員はかけなくなったんだなと思うと感慨深いものがあります。
さて、2025年11月11日、Azure Web Application Firewall(WAF)の「JavaScript チャレンジ」という新機能がFront DoorでGA(一般提供)しました。
本機能はApplication Gatewayでは2025年12月現在パブリックプレビュー中ですが、早速この機能を試してみたので、その体験を共有したいと思います。
JavaScript チャレンジとは?
JavaScript チャレンジは、ボット攻撃からWebアプリケーションを保護するための機能です。ブラウザベースのJavaScriptチャレンジを使って、正規のブラウザからのアクセスとボットによるアクセスを区別できるようになります。
仕組み
Azure WAFでJavaScript チャレンジがアクティブな状態で、クライアントのHTTP(S)要求が特定のルールと一致すると、以下のような流れで処理が行われます:
- クライアントにMicrosoft JavaScript チャレンジページが表示される
- ブラウザがバックグラウンドでチャレンジを計算(ユーザーには数秒間このページが表示される)
- 計算に成功すると、結果がAzure WAFのエンドポイントに送信される
- WAFは要求を非ボットクライアントとして検証し、残りのWAFルールを実行
- チャレンジに失敗した要求はブロックされる
なお、このエンドポイントはパブリックに公開されますが、送信された要求はバックエンドに転送されず、レート制限機能にもカウントされません。
CORS要求とIPアドレス変更への対応
特筆すべき点として、以下のケースでは再度チャレンジが発行されます:
- CORS要求:クライアントが、チャレンジをホストしているドメインとは異なるドメインからJavaScript チャレンジをトリガーするページにアクセスした場合
- IPアドレス変更:クライアントがJavaScript チャレンジを解決した後、IPアドレスが変更された場合
これらの仕様により、セキュリティが保たれる一方で、ユーザー体験への影響も考慮する必要があります。
試してみた手順
Front Doorのプレミアムプランは高額でなかなか試しづらいため、今回はApplication Gatewayで検証を行いました。
繰り返しになりますが、Application GatewayでのJavaScript チャレンジは2025年12月現在パブリックプレビュー中ですのでGA(一般提供)前の機能であることに注意してください。
1. Blob Storageに静的Webサイトをホスト
まず、検証用のコンテンツをホストするために、Azure Blob Storageに静的Webサイトを作成しました。手順については以下のドキュメントを参照してください。
今回は以下のようなシンプルなHTMLファイルを用意しました。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JSチャレンジ成功!</title> </head> <body> <h1>JSチャレンジ成功!</h1> </body> </html>
2. Application Gatewayを作成
次に、Application Gatewayを作成します。今回はAzure portalを使用しました。
まず、レベルを「WAF V2」とし、WAFルールも作成します。この時に「ボット保護の追加」にチェックを入れておきます。

次にバックエンドプールにBlob StorageのエンドポイントのFQDNを指定しました。

あとはIPアドレスの追加やHTTPリスナーの追加などを行いますが、詳細な手順は割愛します。
3. WAFポリシーの確認
作成されたWAFのポリシーを確認します。JavaScriptチャレンジの有効期限を設定できるようになっているのが分かります。デフォルト値はキャプチャの通り30分です。

また、WAFを防止モードに切り替えるのを忘れないようにします。

4. カスタムルールの追加
続いて、カスタムルールを追加します。今回は条件の所はアクセス元のIPアドレスを指定し、結果のアクションで「JSチャレンジ(プレビュー)」を選択します。

5. 動作確認
Application GatewayのパブリックIPアドレスにアクセスすると、JavaScript チャレンジのページが表示されました。数秒後、自動的にBlob Storageのコンテンツが表示されました。

ブラウザの開発者ツールで確認すると、チャレンジに成功すると「appgw_azwaf_jsclearance」というクッキーが保存されているのが分かります。

値がJWT形式のトークンのようなのでデコードしてみると以下のような形でした。
{ "alg": "HS256", "typ": "JWT" }.{ "Data": { "PS": "Global", "PSName": "Global", "State": 2 }, "sub": "xxx.xxx.xxx.xxx", // クライアントのIPアドレス "aud": [ "yyy.yyy.yyy.yyy" // Application GatewayのIPアドレス ], "exp": 17nnnnnnnn.nnnnnn // 有効期限(UNIX時間) }.[Signature]
有効期限もアクセス時間にポリシー設定で指定したタイムアウト時間を追加した値になっていました。
感想
JavaScript チャレンジ機能を実際に試してみて、ボット攻撃対策として非常に有効な手段だと感じました。特に、CAPTCHAのようなユーザーの手間をかけずに、自動的にボットを検出できる点が優れています。
一方で、CORS要求やIPアドレス変更時に再度チャレンジが発行される仕様については、Webアプリケーションの性質によってはユーザー体験に影響を与える可能性があります。導入を検討する際は、実際のユースケースに応じて、この機能の有効化範囲を適切に設定することが重要だと思いました。
JavaScriptチャレンジはApplication Gatewayでは現在パブリックプレビュー中ですが、今後GAとなることで、より多くの環境で活用できるようになることを期待しています。
皆さんの参考になれば幸いです。
サービス一覧 www.alterbooth.com cloudpointer.tech www.alterbooth.com


