HTTP 404が返っても、ボット対策のミドルウェアがリクエストを止めたとは限りません。監視モードでは、拒否すべきという判定が付いていても、その後のルートが実行されます。
この記事では、通常のパスと自分で用意したデコイ用パスを比較し、判定結果・HTTPステータス・ルートの実行を分けて確認します。WebDecoyの開発元による技術解説です。文章と翻訳にAIを使用しています。以下のコードとHTTP応答は、公開済みnpmパッケージでローカル検証しました。
検証する範囲
-
@webdecoy/express0.21.0 -
@webdecoy/node0.21.0 - ローカル検証時のExpressは4.22.3、Node.jsは26.5.0
- APIキーを指定せず、ローカルのtripwireルールのみ使用
- 待ち受けは
127.0.0.1:3000
これは任意のAIボットを識別できるかどうかの精度評価ではありません。自分で送るリクエストによって、指定したパスにルールが一致することと、監視・ブロックの違いを確認する実験です。
1. 公開済みパッケージをインストールする
Node.js 20以降の環境で、空の作業ディレクトリから始めます。
npm init -y
npm install express@4 @webdecoy/express@0.21.0 @webdecoy/node@0.21.0
2. 判定を確認できる小さなアプリを用意する
次を demo.cjs として保存します。
const express = require('express');
const { webdecoy } = require('@webdecoy/express');
const { tripwire } = require('@webdecoy/node');
function createApp(mode = 'monitor') {
const app = express();
app.use(webdecoy({
mode,
rules: [tripwire({ paths: ['/demo-decoy'], includeDefaults: false })],
}));
const decision = (req) => ({
conclusion: req.webdecoyDecision?.conclusion,
tripwire: req.webdecoyDecision?.deniedBy('tripwire') ?? false,
});
app.get('/', (req, res) => {
res.json({ message: 'Ordinary route', decision: decision(req) });
});
app.get('/demo-decoy', (req, res) => {
res.status(404).json({
message: 'Controlled decoy route', decision: decision(req),
});
});
return app;
}
if (require.main === module) {
const mode = process.env.WEBDECOY_MODE === 'enforce' ? 'enforce' : 'monitor';
createApp(mode).listen(3000, '127.0.0.1', () => {
console.log(`Local demo: http://127.0.0.1:3000 (${mode})`);
});
}
module.exports = { createApp };
起動します。
node demo.cjs
/demo-decoy には実際のファイルや秘密情報を置いていません。このサンプルでは判定を見えるようにするため、レスポンスに判定の要約を含めています。本番では同じ情報をサーバー側のログで扱ってください。
3. monitorで通常パスとデコイを比較する
別のターミナルから実行します。
curl -i http://127.0.0.1:3000/
curl -i http://127.0.0.1:3000/demo-decoy
通常のパスはHTTP 200で、次のJSONを返します。
{"message":"Ordinary route","decision":{"conclusion":"ALLOW","tripwire":false}}
デコイ用パスはHTTP 404で、次のJSONを返します。
{"message":"Controlled decoy route","decision":{"conclusion":"DENY","tripwire":true}}
後者の 404 は、デコイ用ルート自身が返しています。monitor ではミドルウェアが後続処理を止めないため、ルートが実行されます。
ルールに一致した根拠は、HTTPステータスではなく req.webdecoyDecision から取り出した conclusion と deniedBy('tripwire') です。
4. ローカルでenforceを明示的に有効にする
Ctrl+Cでサーバーを停止し、次のように再起動します。
WEBDECOY_MODE=enforce node demo.cjs
同じ2つのリクエストを送ると、結果は次のようになります。
| パス | monitor | enforce |
|---|---|---|
/ |
HTTP 200、ALLOW
|
HTTP 200、ALLOW
|
/demo-decoy |
ルートが実行され、HTTP 404、DENY
|
ルートの実行前にHTTP 403で拒否 |
環境変数を付けずに再起動すると monitor に戻ります。実際のアプリへの初回導入では、まず監視モードで通常の利用フローを確認してください。
実運用で確認したいこと
- デコイ用パスを、正当なユーザーが使うパスや実ファイルのパスと重ねない。
- プレビュー、先読み、監視ツール、許可したスキャナーなどからのアクセスも確認する。
- User-Agentの変更だけを、悪意の有無や人間であることの証拠にしない。
- リバースプロキシの手前と奥で観測範囲が異なることを考慮し、
trustProxyは実際の構成に合わせる。 - この構成のローカル判定は、クラウドのダッシュボードへは送信しない。
今回の比較では、両モードの通常リクエストとデコイ用リクエストの計4通りを確認しました。サイト全体の誤検知率、実際の攻撃のブロック率、AIクローラーの網羅性を測定したものではありません。
