- 筆者は Spigot という偽のウェブページ階層構造ジェネレーターを運営しており、攻撃的なウェブクローラーに対してランダム生成されたページを公開している
- 最近、画像クローラーが jpg 画像を探すためにサイトを集中的に探索していることを発見した
- リアルタイム画像生成を最小限の CPU リソースで処理するため、実際の JPEG ファイルの 構造化された部分 だけを集めてテンプレートとして活用し、圧縮された部分にはランダムデータを挿入する方式を提案している
- 実験の結果、この方式で作られた JPEG はエラーを含んでいても、ほとんどの 画像ビューア で画像を表示でき、クローラーにも十分それらしく見える
- この方式は サーバー資源の消費を抑えつつ、クローラーには負担をかけ、Spigot の約 60% のページに適用されている
SpigotとJPEG偽造の背景
- Spigot は Markov Chain ベースで 偽のウェブページ階層 をリアルタイムに生成し、攻撃的なウェブクローラーに無意味なデータを提供する
- 一部のクローラーは正体を隠すために ランダムなブラウザシグネチャ と IP を使用しており、ボットネットを通じた不正なデバイス悪用の可能性が見つかった
- トラフィック分析により、新たなクローラー "ImageSiftBot" が画像収集のために Spigot ページを集中的にリクエストしていることを確認した
- Spigot の主要な目標は サーバー CPU 使用量の最小化 と効率的な動作の維持である
低コストな画像生成方法の検討
- 動的に画像を生成するのは 圧縮 のため CPU 消費が大きく、効率的な方法が必要だった
- JPEG ファイルは、ファイル構造(サイズ、色など)と 圧縮されたピクセルデータ 領域で構成されている点に着目した
- 複数の JPEG から構造化されたヘッダー情報だけを抽出し、ピクセルデータ領域は ランダムデータ で埋める方式が考案された
- こうすることで毎回画像を圧縮する必要がなくなり、その場で生成でき、サーバー負荷を最小化できる
JPEGファイル構造と実装
- JPEG ファイルは 複数のチャンク(マーカーと長さを持つ)で構成される
- ヘッダー/メタ情報は残し、圧縮されたピクセルデータ長だけを記録し、この領域にのみ乱数データを挿入する
- 514 個の JPEG サンプルを使った場合、全ヘッダー情報と必要な構造化データのサイズは約 500KB にすぎず、メモリ負担はごく小さい
- コード例: 各テンプレートのピクセルデータチャンクに乱数を埋め込む方式で画像を生成する
実運用結果とオープンソース公開
- 実際の画像ビューアは、ピクセル領域が 完全な乱数 でもある程度画像を表示できる
- ウェブクローラーはエラーを識別しにくく、データ収集時のコストが増加する
- 1280x960、200〜300KB サイズの JPEG では 1 秒あたり約 900 枚を生成でき、リアルタイム処理にも無理がない
- Spigot 全ページの 60% にこの方式を適用し、URL ベースの乱数シードを使って再リクエスト時にも同じ画像を返す
- ImageSiftBot、Meta、AmazonBot、GPTBot などで高いリクエスト量が観測された
- 中核となる目的は 少ないサーバーリソース で クローラーに負担 をかけることだ
Huffmanコードと追加最適化
- JPEG のピクセルデータは Huffman 符号化 を使用するため、完全な乱数を挿入すると一部のビューアでエラーが発生する可能性がある
- 単純なビットマスキング(0x6D)手法を追加し、1 が 3 個以上連続して現れないようにすることで、不正な Huffman コードが発生する確率を 90% から 4% 未満まで下げた
- 完全に有効な Huffman ストリームを作ることも可能だが、サーバー資源と開発時間に対して得られる利点は小さい
結論
- Spigot の 偽JPEG 生成方式は、圧倒的な効率でサーバーリソースを節約しつつ、クローラーに混乱とリソース浪費を引き起こす
- 関連コードは 100 行未満で、GitHub で公開されている
- シンプルでありながら創造的なウェブトラフィック防御・分散手法である
1件のコメント
Hacker Newsのコメント
robots.txt が /spigot/ ツリーへのロボットアクセスをブロックしているのは予想どおりだったが、URL から /spigot/ だけを外しても引き続き Spigot にアクセスできることを発見した。/~auj ネームスペースは robots.txt でブロックされていないため、善意のクローラーであっても偶然その経路に入ると無限ページループに陥る可能性があり、あまり愉快な状況ではない robots.txt 参考リンク
以前の作者のコメントでは、robots.txt を別途構成していなかったという話があった。ここまで極端な選択をしたことについて、Web サイト運営者がクローラーによる DOS を防ぐためにわざわざ設定しなければならないという考え方が好きではないと述べていた。まともなクローラーなら、1 秒あたり 15 回以上の頻度で 1 つのサイトを継続的にクロールすべきではない、という立場だ
善意のクローラーですら無限ページループに落ちるという点について、Web サイト運営者にスクレイパーへ「親切であるべき」義務がどこまであるのか懐疑的だ。そこまでしなければならないのかは分からない
クローラーが robots.txt を無視していると特定できた場合、「ゴミ」情報を返すよりも、ネットワーク接続を占有したまま放置するほうが効率的だと思う。エンドポイントで無限にゴミを提供する必要性はよく分からない
AI 入力用スクレイパーを撹乱するには、画像ごとに偽のキャプションを付けるのはどうかというアイデアが浮かんだ。たとえば緑色の塊の画像には「猫がキャットニップボールで遊んでいる」と付け、青い画像には「コマドリが巣作りしている」と別の説明を付ける、といった具合だ
最もひどい事例は meta(Facebook)が運用する facebookexternalhit bot だ。このボットは robots.txt を無視すると公式に文書化されている。Facebook では悪意あるリンク検出のためとしているが、実際には悪意のある利用者が高コストなエンドポイントの URL を Facebook に繰り返し送るだけで、Facebook が代わりにトラフィック爆撃をしてくれるようなものだ。その結果、毎月数日間、1 日中 10 r/s 以上のトラフィックがサイトに流れ込む
Spigot に関する話を読んでいて Project Honeypot を思い出した。20 年前、このプロジェクトのスクリプトと自分が寄付した MX レコードが自分のサイトでメールハーベスターを捕まえるのに役立った、というメールを受け取るたびにかなりワクワクしたものだ。たとえば、自分の MX のおかげで未確認のスパム送信者(IP: 172.180.164.102)を捕捉した、と通知されるような具合だ
JPEG を偽造するのは、正しく生成するより CPU 負荷がはるかに低い。しかもこの過程自体が、相手側マルウェアの JPEG デコードが甘ければクラッシュを誘発する、一種の fuzzing の役割も果たしうる
最近の流入トラフィックが何千もの家庭用 IP から来ているからといって、必ずしも典型的なボットネットとは限らない。むしろ、多くの人が「無料 VPN」や「受動的収益生成」ツールに登録し、自分のデバイスが他人のトラフィックの出口ノードになるような「proxyware」の仕組みかもしれない。この場合、本人が知らないうちに AI クローラーのトラフィック経路になっている可能性がある 関連参考資料
結局のところ、この種の proxyware もユーザーが自発的に参加したボットネットの亜種だ。こうしたユーザーが HN のような場所で自分の IP が問題になっていると気づくこともなさそうなので、誰かが IP を別途「あなたはボットネットの一部です」と警告するページへ誘導するのも悪くないと思う。現実的には、とにかく全部ブロックするのがいちばん楽だ
これも十分にボットネットの範疇に入る構造だという意見だ
ボットを満足させる方法について語る語り口が印象的だった。面白い記事だったし、プロジェクトも興味深い
「与えられた任務に悪戦苦闘するボットが気の毒で、楽しませる方法を考えた」という姿勢がとても新鮮で面白い。たいていは怒りや不満に満ちたスレッドとは明らかに違う
このリンク先の成果物(画像)が気に入った 画像を見る。ある種のメッセージを込めたアート作品のようだ
本物の Spigot 体験をしたいなら、Firefox では F12 > Network > No Throttling を GPRS に変更し、Chromium では F12 > Network > Custom profile を 20kbps に設定して速度制限をかけると、それらしく体験できる
ここに Shakespeare 関連のコンテンツもあるのだろうかと気になる