template-wa.php

アーカイブ動画

--------------------------------

はじめに

自動化ブラウザやアンチディテクトブラウザ(フィンガープリントを偽装して検出を回避するブラウザ)は、クレデンシャルスタッフィング、アカウント乗っ取り、アドフラウド、スクレイピング、そしてセキュリティ対策の回避に、ますます多く使われるようになっています。防御側の視点で見ると、問われているのはもはや「これはボットなのか?」だけではありません。「この環境は、本物のブラウザのふりをしていないか?」——そして、もしそうだとすれば、どうすれば確実に見分けられるのか、という点です。

本記事では、自動化ブラウザとアンチディテクトブラウザを実用的に検出する手法を確立するために取り組んだ、リサーチプロジェクトを紹介します。目指したのは、セッションが自動化によって操作されている場合や、フィンガープリントを偽装する改変環境で動作している場合を——たとえそのブラウザが標準的なChrome、Firefox、Safariなどを名乗っていたとしても——特定し、Webアプリケーションを保護できる技術を作ることです。

ここでは、相互に補完し合う3つのアプローチに焦点を当てます。実行ファイルの解析、環境フィンガープリントの比較、そして挙動のインターセプトです。さらに、自動化フレームワーク(Playwright、Puppeteer、Selenium)を使って、これらの環境を露呈させる挙動を意図的に引き起こし、相関を取る方法も示します。具体例として、アンチディテクトブラウザであるAntBrowserにこれらの手法を適用し、そこから見えてくる検出シグナルを解説します。

セキュリティにとって、なぜこれが重要なのか

正規のユーザーは、通常のブラウザを使います。一方で、攻撃者や不正利用者がよく用いるのは次のようなものです。

  • 自動化ブラウザ(Selenium、Playwright、Puppeteerなどで操作されるもの):クリック、フォーム入力、画面遷移をスクリプトで実行します。
  • アンチディテクトブラウザ:本物のブラウザを装いつつ、canvas、WebGL、フォント、画面解像度などのフィンガープリントを改変し、自動化の痕跡を隠すこともあります。

どちらも、一見すると普通のUser-Agentを返し、JavaScriptをサポートし、単純な「ボットか人間か」のチェックは通過してしまいます。だからこそ、検出はより深いレイヤーへ踏み込む必要があります。実行ファイルから得られるシグナル、ブラウザが公開している環境(オブジェクト、API、ネイティブコードかスクリプトか)から得られるシグナル、そして特定の関数がいつどのように呼ばれるか——とりわけ自動化操作に反応して呼ばれるかどうか——というシグナルです。

検出手法1:実行ファイルとプロセスの解析

最初に着目するのは、バイナリそのものです。自動化ブラウザやアンチディテクトブラウザは、独自の実行ファイル(Chromiumベースのビルドなど)として配布されることが多く、名前、パス、メタデータに特徴が現れます。

私たちが行うこと

  • ブラウザ実行ファイルのプロセス名とパスを確認する。
  • ディスク上の実行ファイルのバイナリから、特徴的な文字列(製品名、自動化関連のキーワード、ベンダー固有の識別子)を探索する。
  • それらの文字列を、既知の“クリーンな”ブラウザビルドのベースラインと比較する。
  • 場合によっては、実行後にプロセスメモリを調べる(メモリダンプを取得すると容易)ことで、通常は隠されている情報が得られます。たとえば、ディスク上の文字列がエンコードまたは暗号化されているケースです。

なぜ有効なのか

アンチディテクト系や自動化系の製品の多くは、Chromium(あるいは他のエンジン)をフォーク、またはリブランドしており、バイナリの内部に識別可能な文字列を残しています。User-AgentやJavaScript APIの上で製品名を隠していても、ディスク上の実行ファイルが正体を語ってしまうのです。マッチが見つかれば、誤検知が少なく、確度の高いシグナルになります。

制約:この手法は通常、クライアント環境へのアクセス(エージェントの導入や、管理下のデスクトップなど)が前提になります。サーバー側がHTTPとJavaScriptしか観測できない「Webサイトのみ」の文脈では、適用しづらい方法です。

検出手法2:環境フィンガープリントの比較(windowとDOMの列挙)

2つ目の手法は、ブラウザ上でJavaScriptを実行できることを前提とします。ブラウザのグローバル環境(windowなど)とDOMを一種のフィンガープリントとして扱い、プロパティ、オブジェクト、関数を列挙したうえで、そのクライアントが名乗っているブラウザとバージョンの“正常なベースライン”と比較します。

私たちが行うこと

  • 再帰的な列挙ツールを使い、到達可能なすべてのプロパティと要素を走査して、次を記録する。
  • 特定の変数やAPIが存在するか、しないか。
  • 型(function、objectなど)と、必要に応じて値やシグネチャ。
  • 実際の未改変ブラウザ(例:「Windows 11上のChrome 140」「macOS上のFirefox 139」)から、ベースラインのスナップショットを作成する。
  • 未知のクライアントが「Chrome 140」を名乗ってきた場合、そのスナップショットを本物のChrome 140のベースラインと比較する。

着目するシグナル:

  • 欠けているプロパティ/余分なプロパティ: 名乗っているブラウザには存在するはずのAPIやグローバル変数が存在しない(あるいはその逆)。
  • ネイティブではない実装: 本来ネイティブであるはずの関数(特定のDOMメソッド、evalFunctionなど)が、ネイティブでないJavaScript(ラッパー、ポリフィル、計装コードなど)を含んでいる、または参照している。.toString()の結果を既知のネイティブ実装と比較すると、パッチやフックの存在が明らかになることがよくあります。

なぜ有効なのか:

アンチディテクトや自動化のフレームワークは、自動化を隠したりフィンガープリントを変えたりするために、コードを注入し、ネイティブAPIを置き換え、環境そのものを改変します。こうした変更は、必ず痕跡を残します——余分なオブジェクト、書き換えられた関数本体、欠落または追加されたプロパティです。同じブラウザ・同じバージョンのクリーンなベースラインと比較することで、これらの差分を高い精度で検出できます。

検出手法3:挙動のインターセプト(関数フックと相関分析)

3つ目の手法が見るのは挙動です。可能な限り多くのグローバル関数をフックし、それらがいつどんな引数で、どこから(コールスタック)呼ばれたのかを観測します。実際のユーザーセッションで呼ばれるのは、そのごく一部の関数にすぎません。ところが自動化環境やアンチディテクト環境では、計装や自動化の存在を露呈させる想定外の呼び出しが、数多く観測されます。

私たちが行うこと:

  • 関数の列挙・フックツールを使い、次を行う。
  • windowとその配下のオブジェクトから、関数を再帰的に発見する。
  • 発見した各関数をフックでラップし、以下を記録する。
    • 関数のパス(例:Element.prototype.setAttribute)。
    • 引数と、可能であれば戻り値。
    • 誰が呼び出したのかを把握するためのコールスタック(呼び出し元・呼び出し先)。
  • フックを仕込んだページを、次の環境で読み込む。
    • 実際のブラウザ(ベースライン)。
    • 調査対象(自動化ブラウザやアンチディテクトブラウザなど)。
  • 同じユーザーフロー(あるいは操作を行わない状態)で、どの関数が呼ばれたかを比較する。自動化環境やアンチディテクト環境でのみ発生する呼び出し——特に、スタックトレースが自動化ツールやベンダー側のコードを指しているもの——は、強力な検出シグナルになります。

なぜ有効なのか:

自動化ランタイムやアンチディテクトのレイヤーは、実際のコードと同じDOMやJavaScript APIを介して動作するほかありません。そのため、通常のページでは起こらないタイミングや方法でAPIを呼び出すことになります(合成イベント、内部的な管理処理、フィンガープリントの偽装など)。たとえばElement.prototype.setAttributescrollIntoViewが、Playwright/Puppeteer/Selenium、あるいはアンチディテクト用スクリプトを含むスタックから呼ばれていれば、自動化または改変の明確な指標となります。

自動化フレームワークとの相関:

さらに一歩進めることもできます。同じページをPlaywright、Puppeteer、Seleniumで操作し(「マウスを(x, y)へ移動」「クリック」「入力」など)、どのフック関数が発火するかを記録するのです。その後、本番サイトでまったく同じ呼び出しパターンが観測されれば、テストラボに自動化フレームワークが存在しなくても「自動化と同じ挙動をしている」と判定し、検出ルールとして展開できます。つまりラボが、シグネチャの製造工場になるわけです。「Playwrightでマウスを動かすと、これらのAPIがこの順序で呼ばれる。ライブセッションで同じパターンを観測したら、自動化とみなす」という具合です。

手法を組み合わせる:実践的なワークフロー

  1. ベースラインの収集: クリーンなVM上の本物のChrome、Firefox、Safari(および各バージョン)で、要素抽出ツールと関数フックスクリプトを実行し、スナップショットと呼び出しパターンのベースラインを保存します。
  2. 調査対象の解析: 同じツールを自動化ブラウザやアンチディテクトブラウザの内部で実行します。自動化(Playwright/Puppeteer/Selenium)でページを操作する場合と、しない場合の両方を試します。
  3. 差分抽出とトリアージ: スナップショット(欠落/余分なプロパティ、ネイティブでないコード)と、呼び出しログ(想定外の関数、自動化に紐づくスタック)をそれぞれ比較します。
  4. シグネチャの作成: 繰り返し現れる差分を、検出ルールへ落とし込みます(例:「このプロパティが欠けており、かつこの関数がこのパスから呼ばれていればアンチディテクトとしてフラグ」「このAPI呼び出しの並びがPlaywrightのプロファイルと一致すれば自動化としてフラグ」)。
  5. 展開: これらのルールを保護レイヤー(サーバーサイドまたはクライアントサイド)へ実装し、疑わしいセッションにタグ付けやブロックを適用します。

各ステップで取得したスクリーンショットやログは、調査結果のドキュメント化や、誤検知のチューニングに活用できます。

ケーススタディ:AntBrowser

AntBrowserとは?

AntBrowserは、1台のマシンから複数のアカウントやアイデンティティを管理したいユーザー——アフィリエイトマーケター、SNS運用担当者、EC事業者など——に向けたアンチディテクトブラウザです。Chromiumベースで構築されており、Windows、macOS、Linuxで利用できます。ベンダーは、それぞれ異なるデジタルフィンガープリントを持つ独立したブラウザプロファイルを作成できるツールとして訴求しており、各プロファイルはWebサイトからは別々のデバイスやユーザーとして見えます。ロシア語圏の市場や、VK、Avitoといったプラットフォームで支持を広げています。

典型的なユースケース:

  • 複数のSNSアカウントや広告アカウントを、アカウント同士の紐づけを検出されずに運用する。
  • 1台のコンピューターから、複数のECアカウントや暗号資産取引所アカウントを運用する。
  • 同一ユーザーが複数アカウントにアクセスする際、フィンガープリントによる名寄せを回避する。

検出リサーチにおける重要性:

AntBrowserのようなアンチディテクトブラウザは、セキュリティ製品が自動化や不正の検出に用いているシグナルの多くを、改変または隠蔽しなければ成立しません。つまり、コードを注入し、ネイティブAPIを上書き・ラップし、環境のプロパティを書き換えているということです。私たちのアプローチは、まさにそうした改変を見つけ出すために設計されています。

わかったこと(概要):

前述の手法——特に環境比較(window/DOMの列挙)と関数のインターセプト——により、同一バージョンの未改変Chromiumビルドと比べて、AntBrowserを識別できる複数の挙動を特定できました。私たちが着目するシグナルの例は、次のようなものです。

  • クリーンなブラウザでは同じフローで発生しない、DOM/APIメソッドへの想定外の呼び出しや、繰り返しの呼び出し
  • ネイティブに見えるAPIが呼ばれた際に、AntBrowserやその計装コードを指し示すスタックトレース
  • AntBrowserのスナップショットを本物のChrome/Chromiumのベースラインと比較したときの、グローバル環境の差分(余分なオブジェクト、標準関数の改変やネイティブでない実装など)。

Chromeの実行ファイルから取得したstringsの一部には、「window.system.base64_encode」という関数の存在を示す記述が含まれていました。

通常のブラウザには存在しないはずの関数ですが、AntBrowserには実際に存在し、しかもstringsの出力で確認したものとまったく同じ定義を持っていました。

AntBrowserのセッションで確認された、ネイティブではない関数実装の例です。

一方、同じ種類・同じバージョンの通常のブラウザであれば、次のような結果が得られるはずです。

また、一見するとネイティブコードを返しているように見えても、書き換えが適切に行われていないケースもありました。

スタックトレースなどの情報を取得するためのフック機構を示した図です。この例では、最初の呼び出しを自作の関数から行っていますが、実際の環境では、スクロールなどの操作を自動実行するようブラウザに指示した時点で、複数の不正ブラウザが同じ挙動を示します。

これらの発見により、User-Agentをはじめとする表層的な指標が偽装されていても、AntBrowser(および類似製品)を検出できるルールを構築できます。

防御側にとっての示唆

  • 多層的な検出: 単一のシグナル(User-Agentや、1つのJavaScriptプロパティなど)に依存する検出は脆弱です。実行ファイルの解析(可能な場合)、環境フィンガープリントの比較、挙動のインターセプトを組み合わせることで、はるかに堅牢な全体像が得られます。
  • ベースラインが決定的に重要: 実際のブラウザ(とそのバージョン)について、最新のベースラインを維持することが不可欠です。ブラウザは進化し続けるため、ベースラインを更新しなければ、新しい正当な挙動を悪性と誤判定しかねません。
  • シグネチャの供給源としての自動化: Playwright、Puppeteer、Seleniumでページを操作し、どのAPIが呼ばれるかを記録すれば、「自動化らしい」挙動シグネチャを反復可能な形で生成できます。これは、保護対象のサイト自身が自動化を実行していなくても活用できる方法です。
  • アンチディテクトは動く標的: ベンダー側も必ず適応してきます。検出ロジックは、更新しやすい設計(新しいスナップショット差分、新たにフックするAPI、新しいスタックパターンの追加)にしたうえで、ブラウザやアンチディテクトツールの変化に合わせて、誤検知を継続的に監視する必要があります。

結論

自動化ブラウザやアンチディテクトブラウザの検出には、表層的なチェックを超えて、複数の手法を組み合わせることが求められます。ブラウザ実行ファイルの解析、JavaScriptおよびDOM環境と“正常なベースライン”との詳細な比較、そして関数フックと自動化フレームワークとの相関による挙動分析です。本プロジェクトは、こうしたアプローチが実現可能であり、AntBrowserに対する取り組みが示すとおり、具体的で実運用に耐える検出につながることを実証しています。

私たちは今後も手法の改良を重ね、新しいブラウザバージョンのベースラインを追加し、新たな発見を(スクリーンショットや無害化した例とともに)記録・共有していきます。

最新の記事