アプリケーションに到達する前に偽のクローラーをブロックするサーバーミドルウェア

ウェブアプリケーションのリクエストパイプラインは優雅な仕組みです。リクエストはウェブサーバーに到着し、一連のミドルウェアを通過し、コントローラーに到達し、レスポンスを返します。スタック内の各ミドルウェアは、リクエストを検査し、変更し、通過させ、または完全に拒否する機会があります。このアーキテクチャはボット検出の実装に最適です。検証はリクエストがアプリケーションロジックに触れる前に行われるためです。Googlebot を装った偽のクローラーはミドルウェアレイヤーで識別されてブロックされ、コントローラーはそのリクエストが存在したことすら知りません。ページをレンダリングするためにCPUサイクルが消費されることはありません。データベースクエリが実行されることもありません。キャッシュエントリが設定されることもありません。偽のボットは玄関でブロックされ、消費されたはずのサーバーリソースは正規のビジターのために保持されます。

このミドルウェアを構築する動機は具体的で費用的な問題から生まれました。大規模なアプリケーションは、実際のユーザーベースと相関しないレートで帯域幅とサーバーリソースを消費していました。アクセスログはGooglebot、Bingbot、およびその他の正規のクローラーを装ったリクエストの膨大なボリュームを明らかにしていました。調査で、これらの大多数は偽物であり、クローラーが主張するサーチエンジンではなくクラウドホスティングプロバイダーから発信されていることが確認されました。各偽のリクエストは本物のリクエストと同じサーバーリソースを消費していました。同じPHP実行時間、同じデータベースクエリ、同じメモリ割り当て、同じレスポンス帯域幅です。1時間あたり数千の偽のリクエストを乗算すると、コストは相当でした。ミドルウェアソリューションは、アプリケーションリソースをまったく消費する前に偽のクローラーをキャッチすることで、この浪費を排除するために設計されました。

実装はバックエンドの開発者であれば誰でも適応できる単純なパターンに従っています。ミドルウェアはすべての受信リクエストをインターセプトし、ユーザーエージェント文字列が既知のサーチエンジンクローラーパターンと一致するかどうかを確認し、一致した場合はボット検出APIを使用してリクエストのIPアドレスをクローラーの既知のインフラストラクチャに対して検証します。検証に失敗したクローラーを装うリクエストは403レスポンスでブロックされます。検証に合格したリクエスト、またはクローラーを装わないリクエストは、通常どおりミドルウェアスタックを通過します。検証結果はIPアドレスごとにキャッシュされるため、各ユニークIPは1回だけ検証されるため、チェック全体は最小限のレイテンシを追加します。

ミドルウェアレイヤーでブロックする決定ロジック

ウェブサーバーレベル(NginxまたはApache)またはアプリケーションレベル(コントローラー内)でブロックするのではなく、ミドルウェアレイヤーでブロックすることを選択することは、特定のトレードオフを伴う意図的なアーキテクチャ決定です。ウェブサーバーレベルでのブロックは、リクエストがPHPに到達しないため、リソース消費の観点からは最も効率的なオプションです。ただし、ボット検出のためのウェブサーバー設定は通常、静的IPブラックリストまたは単純なユーザーエージェント一致を含みます。どちらも、本当のクローラーと偽のクローラーを正確に区別するために必要な動的でAPIドリブンの検証を提供しません。数百万のIPアドレスの静的ブラックリストを維持することは実用的ではなく、ユーザーエージェント一致だけではIDを検証できません。ユーザーエージェントは簡単に偽造できるためです。

アプリケーションレベル内、コントローラーまたはサービスクラス内でのブロックは、最も柔軟なオプションですが、最も効率的ではありません。リクエストがコントローラーに到達するまでに、ミドルウェアスタックは既に実行され、ルートは解決され、セッション初期化と認証などの潜在的に高コストの操作は既に実行されています。この時点でブロックするとコントローラー実行時間は節約されますが、その前に発生したすべてのものを浪費します。偽のボットリクエストが1時間あたり数千である高トラフィックアプリケーションの場合、この無駄な前処理は蓄積されます。

ミドルウェアレイヤーはパイプラインの最適なポイントに位置しています。セッション処理の前、認証の前、ルート固有のミドルウェアの前、確実にコントローラーロジックの前に実行されます。しかし、ヘッダー、IPアドレス、クエリパラメータを含む完全なリクエストオブジェクトにアクセスできます。つまり、単純なパターンマッチングではなく、高度な検証ロジックを実行できます。ミドルウェアは外部APIを呼び出し、結果をキャッシュし、宣言されたIDに基づいて条件付きロジックを適用し、検証結果をログに記録して分析することができます。この効率性と柔軟性の組み合わせにより、ミドルウェアはウェブアプリケーションのボット検出の自然な場所になります。

キャッシュ戦略は特にパフォーマンスにとって重要です。キャッシュなしで、宣言されたクローラーからのすべてのリクエストはIPアドレスを検証するためにAPIコールが必要になります。高速APIでさえ、これはすべてのリクエストにレイテンシを追加します。解決策は、IPアドレスでキーイングされた検証結果をキャッシュし、数時間またはさらには丸1日のTTLを設定することです。サーチエンジンクローラーは安定したIPレンジから操作され、これらのレンジはめったに変わりません。つまり、キャッシュされた検証結果は長期間有効なままです。宣言されたGooglebot からのリクエストが到着すると、ミドルウェアはまずキャッシュをチェックします。IPがキャッシュ期間内に正規として検証された場合、リクエストは即座に通過されます。IPが偽として検証された場合、即座にブロックされます。初回のIPアドレスのみが実際のAPIコールを必要とし、その後、結果はわずかなレイテンシコストでキャッシュから提供されます。

ブロックされるリクエストに起こること

偽のクローラーをブロックすることは、単に403レスポンスを返して進むことではありません。ブロック決定とそのコンテキストは分析のためにログに記録される必要があります。すべてのブロック済みリクエストは、サイトにアクセスしようとしている人、何を装おうとしているのか、どこから来ているのかに関するデータポイントを表します。時間とともに、このログはより広いセキュリティ決定に情報を与えるパターンを明らかにしています。特定のASNが偽のクローラーの不均衡なシェアの原因となっているかもしれません。偽のGooglebot リクエストが特定の時間に急増するかもしれません。特定のURLパスが他のものより多くの偽のクローラーを引き付けるかもしれません。これはボットが特定のコンテンツを対象としていることを示唆しています。

ブロック済みリクエストへのレスポンスは、一律の403よりもニュアンスに富んでいる可能性があります。一部の実装は429(Too Many Requests)を返して、ボットが識別されたという事実を隠し、ボットオペレーターが彼らのアプローチを調整するのを難しくします。その他は、ボットが検出されたことを知ることを防ぐ一方で、最小限の帯域幅を浪費する200を空のボディで返します。より積極的なアプローチは、クローラー検証が失敗したことを示すメッセージを含む403を返し、これは透過的ですがボットオペレーターに検出メカニズムに関する情報を与えます。選択はサイトオペレーターの透明性と運用上のセキュリティに関する哲学に依存します。

クローラーを装うがサーチエンジンのユーザーエージェント文字列を誤って使用する正規のサービスである実際のボットの場合、ブロックは意図したものより破壊的である可能性があります。SEO監視ツールはGooglebot のようなユーザーエージェントを使用してGoogleがページをどのように見ているのかをシミュレートします。これらのツールはGoogle ではないため検証に失敗します。ただし、それらの目的はサイトオペレーターの観点からは正規のものです。ミドルウェアはクローラーのようなユーザーエージェントを誤って使用する信頼できるサードパーティサービスの既知のIPレンジのホワイトリストを維持することで、これに対応できます。または、検証をすべてを無視しながら特定のユーザーエージェントパターンにのみ適用します。ミドルウェアアプローチの柔軟性により、ウェブサーバー設定やアプリケーションコードの変更を必要とすることなく、この種の細かいポリシーが可能です。

同期対非同期検証

ボットを同期または非同期で検証するかどうかの質問は、ブロックの有効性とアプリケーションへのパフォーマンス影響の両方に影響します。同期検証は、ミドルウェアがリクエストを一時停止し、検証APIを呼び出し、レスポンスを待機し、結果に基づいてリクエストを許可またはブロックすることを意味します。このアプローチは即座のブロックを提供しますが、各IPアドレスからの最初のリクエストにレイテンシを追加します。キャッシュでは、レイテンシは最初のリクエストにのみ影響しますが、高トラフィックアプリケーションの場合でも、その時折の遅延は許可できないかもしれません。

非同期検証は異なるアプローチを取ります。新しいIPからの最初のリクエストは検証ジョブがバックグラウンドでキューイングされている間に通過されます。検証結果が戻ると、キャッシュされ、そのIPからのすべての後続リクエストは結果に従って処理されます。このアプローチはリクエストパイプラインにゼロレイテンシを追加しますが、検証が完了する前に偽のボットからの少数の初期リクエストが通過することを許可します。ほとんどのアプリケーションでは、このトレードオフは受け入れられています。ブロックされる前に3つのリクエストを送信する偽のボットは、検出されずに数千のリクエストを送信するボットよりもはるかに少ないリソースを消費しています。

キューシステムは非同期アプローチを簡単にします。ミドルウェアはボット検出APIを呼び出し、結果をキャッシュに保存し、オプションでアプリケーションの他の部分がリッスンできるイベントを発火させる検証ジョブをディスパッチします。ジョブは数秒で実行されます。つまり、未検証のボットトラフィックが通過できるウィンドウは極めて小さいです。高速なメモリ内キャッシュを使用するアプリケーションの場合、キャッシュされた結果はすべてのアプリケーションインスタンスに即座に利用可能です。ロードバランス環境でさえ、検証はIPアドレスごと、すべてのサーバーで1回だけ実行される必要があります。

ハイブリッドアプローチは双方の最良の側面を組み合わせます。高信頼性パターンと一致する既知のボットユーザーエージェントは同期検証をトリガーし、キャッシュされた結果でわずかなレイテンシを追加します。低信頼性パターンは非同期検証をトリガーし、検証がバックグラウンドで実行されている間に最初のリクエストが通過されます。この段階的なアプローチは一般的なケースのために最適化し、エッジケースを優雅に処理します。ミドルウェアのリクエストパイプラインでの位置により、このロジックを実装するのに最適な場所になります。ルーティング決定を行うために必要なすべての情報にアクセスでき、高コストなアプリケーションロジックの前に実行されるためです。

玄関でブロックすることの測定可能な影響

ボット検出ミドルウェアを実装した結果は、サーバーメトリクスでほぼ即座に目に見えます。最も劇的な変化は帯域幅消費です。偽のクローラーは完全なHTMLページをリクエストします。レスポンスで参照されているすべてのアセットを含みます。各ブロック済みリクエストは、完全なレスポンスを送信するために使用される帯域幅を節約します。コンテンツが多いページの場合、リクエストあたり数十または数百キロバイトになる可能性があります。1時間あたり数千のブロック済みリクエストを超えて、帯域幅の節約は意味のあるコスト削減に蓄積します。特に、1ギガバイトあたりの転送に対して課金するプロバイダーでホストされているアプリケーションの場合です。

CPUの使用率が低下します。サーバーは、値を生成しないリクエストのためにPHPコードを実行したり、データベースクエリを実行したり、テンプレートをレンダリングしたりしないためです。削減は、人間のトラフィックが低いが、ボットトラフィックが一定のままのピーク時間外で最も顕著です。ミドルウェアを実装する前は、ボットは眠らないため、サーバーは深夜3時でも基本的なCPU使用率を維持していました。実装後、ピーク時間外の使用率はほぼゼロに低下し、ピーク時間中の正規のトラフィックのためにサーバーに余裕を与えます。

正規のビジターのレスポンスタイムは、サーバー負荷の低下の直接的な結果として改善されます。1秒あたり500のリクエストを処理するウェブサーバー。そのうち300は偽のボットで、200人の正規のビジターよりも少ない容量があります。1秒あたり200のリクエストのみを処理するサーバーで、すべてが正規のサーバーです。ミドルウェアはブロック済みリクエストのリソースを節約するだけではありません。すべてのリクエストが通過するサービスの品質を改善します。サーバーが実際の作業に利用できる容量が多いためです。

データベース負荷は比例して減少します。アプリケーションがすべてのページリクエストのためにデータベースをクエリする場合、300の偽のリクエストをブロックすることは1秒あたり300の不要なデータベースクエリを排除します。複雑なクエリまたは制限されたデータベース接続を持つアプリケーションの場合、この削減は安定した操作と周期的なオーバーロードの違いになる可能性があります。ミドルウェアは、不要なトラフィックをそれに到達する前にブロックすることで、ウェブサーバーからアプリケーションレイヤーをデータベースまで、スタック全体を保護します。

よくある質問

ボット検出ミドルウェアを追加すると、実際のユーザーのサイトが遅くなりますか?

実際のユーザーにとって、ミドルウェアは無視できるオーバーヘッドを追加します。ユーザーエージェント文字列をクローラーパターンに対してチェックします。これはマイクロ秒で行われます。クローラーを装うとの主張をするリクエストのみが検証ロジックをトリガーします。キャッシュされた結果でさえ、APIはIPアドレスごとに1回だけ呼び出されます。定期的なビジターはレイテンシの測定可能な増加を経験しません。

ボット検出APIが一時的に利用不可の場合、どうなりますか?

ミドルウェアにはフォールバック戦略を含める必要があります。一般的なアプローチは、APIに到達できない場合、リクエストを許可することです。検証サービスの障害が正規のクローラーをブロックしないようにするため。以前キャッシュされた結果はAPI ダウンタイム中も機能し、短いサーキットブレーカーパターンはパフォーマンスの低下から失敗したAPIコールの繰り返しを防止します。

このミドルウェアアプローチは、任意のウェブフレームワークで機能しますか?

ユーザーエージェントをチェックし、IPアドレスを検証し、結果をキャッシュするコアロジックはフレームワークに依存しません。ミドルウェアパターンはすべての主要なウェブフレームワークに存在します。APIコールとキャッシュロジックは任意のフレームワークのミドルウェアまたはイベントシステムに適応することができます。重要な原則は技術に関係なく同じです。早期にインターセプト、IPで検証、結果をキャッシュします。

正規のツールが偽のボットとして誤認識される偽陽性を処理するにはどうすればよいですか?

クローラーのようなユーザーエージェントを使用する既知の正規のツールのIPレンジのホワイトリストを維持します。ミドルウェアは検証を実行する前にホワイトリストをチェックし、信頼できるサービスをAPIコールなしで通過させます。検証ログはどのIPアドレスがブロックされているのか、それらの関連するASN情報を表示することで、偽陽性を識別するのに役立ちます。

偽のボットを403または別のステータスコードでブロックする必要がありますか?

選択はあなたの目標に依存します。403は明確にアクセスが拒否されていることを伝えます。429は検出機能を明らかにしないでレート制限を示唆しています。200 を空のボディで返すと、ボットオペレーターに最も情報が与えられません。ほとんどのアプリケーションでは、403が最も簡潔で標準に準拠した選択です。

IPの検証キャッシュはどのくらいの頻度でリフレッシュする必要がありますか?

サーチエンジンのIPレンジはめったに変わらないため、ほとんどのアプリケーションではキャッシュ期間が12から24時間は安全です。短いキャッシュ期間はAPIコール量を増加させますが、より新しい検証データを提供します。ほとんどのサイトでは、24時間のキャッシュが精度と効率の間の正しいバランスを取ります。