



スパム判定の基準は各サービス、あるいはユーザ毎の設定によっても変わってくるので、判定ロジックはプラグイン形式になっており、判定時にはこれらのプラグインが並列で動作する仕組みになっています。リクエスト時に必要なプラグインを指定し、任意の組み合わせで利用できます。

ピンク色になっているのがスパムと判定されたコメント/トラックバックです。左側に判定対象のデータの詳細、右側に判定に参加したプラグインの一覧が表示されています。
ライブドアブログ宛のコメント/TBについては、現在デフォルトで10種類のプラグインが判定に参加する設定になっています。
シンプルなブラックリスト方式 (あらかじめ登録されたブラックリストに、URLの一部または全部がマッチするかどうかテストする、など) から、過去の統計情報を元に判定するもの (大量の類似テキストを検出する判定や、ベイジアンフィルタによる判定など) まで、様々な観点からスコアリングをするプラグインがありますが、そのうち、0以上のスコアを返したもの (該当データがスパムの可能性がある、と判定したプラグイン) が太字で表示されています。
たとえば、一番上の投稿についてはNaiveBayesプラグイン(ベイジアンフィルタを用いてスパム判定をするプラグイン) が 0.98 (98%) の確率で、ReportedSpammersプラグイン(以前スパムと判定されたデータと送信元IPなどの共通点があるかどうかを基にスパム判定をするプラグイン) が 0.4 (40%) の確率で、SimilarTextsプラグイン(似たようなテキストの大量投稿を検出するプラグイン) が 0.7 (70%)の確率で、それぞれ「スパムである」という結果を返しています。
これらの結果を総合して、このデータについてはscore:0.99...、すなわち「0.99(99%)の確率でスパムである」という判定を下した、というのがこの管理画面の表示の見方です。
2番目、3番目のデータについては、同様にそれぞれ 0.6 (60%)、0 (0%) という判定になっています。0.6を超えたらアウト、というのがおおよその基準です。

まず、判定対象のデータが、クライアントからスパムちゃんぷるーのwebサービス宛に送信されてきます。



このときの計算方法ですが、基本的な考え方は「スパムでない確率 = すべてのプラグインから見てスパムでない確率」です。(例えば、送信元や本文にはスパムの痕跡はまったく見られないが、本文が明らかに他のスパムと同じものである場合、これはやはりスパムと判定されます。)
従って、例えばプラグインAが 0.4 (40%)、プラグインBが 0.3 (30%)、プラグインCが 0 の確率でそれぞれスパムである、と判定した場合、「プラグインA〜Cのいずれから見てもスパムでない確率」は (1 - 0.4) x (1 - 0.3) x (1 - 0) = 0.42 (42%) となり、最終的なスパム確率 =「プラグインA〜Cのいずれかから見てスパムである確率」は 1 - 0.42=0.58 (58%) となります。

基本としては、"SpamChampuru::Plugins::Worker" クラスを継承し、$data を受け取ってスコア(0〜1)を返す "score" というメソッドを定義するだけです。

あとはこのように、body 部分に "hello, world" というテキストが入った判定対象データと、"HelloWorld" プラグインを使用して判定せよ、という指定をして XMLRPC 経由で呼び出せば、判定結果 (score = 1) が返ってきます。

分岐後、各子プロセスはまず init() メソッドに入ります (init phase) 。ここで必要に応じて db に接続し、最新のプラックリストを取得するなどします。
init phase が終わると、いよいよ score() メソッドに処理が移り、実際に gearman の worker としてスパム判定に参加します (main loop) 。
db の処理はなにかとボトルネックになりがちなので、必要なデータは先の init phase ですべてオンメモリにしておき、main loop 内ではできるだけ db には接続しないようにしています。 ただ、そうすると、時間が経つにつれて持っているデータが up-to-date でなくなってきてしまうので、定期的に init phase に再移行する仕組みがあります。
mother process は、各子プロセスに対して定期的にシグナル SIGUSR1 を送ります。SIGUSR1 を受け取った子プロセスは、(現在の score() の処理が終わり次第) init phase に再突入します。
プラグインの種類によっては、定期的にプロセスの再起動をした方が安全なものがあります。その場合は、init phase ←→ main loop のサイクルが一定回数終わった時点で SIGTERM が送られ、子プロセスは終了します。 mother process は子プロセスが生きているかどうかも定期的にチェックしているので、終了したプラグインプロセスは再度 fork により起動し直されます。

そこで実際には、子プロセスはプラグインの種類毎にペアあるいはそれ以上で起動されます。mother process は、同じプラグインを受け持つ子プロセスが同時に init phase に突入しないように、シグナルの送信間隔を分散させています。

先に述べたように、worker-mode plugin は、あらかじめ db に格納されている集計済みデータ、ブラックリストなどを基に高速に判定を行うのが目的です。これらの判定の元になるデータは、バッチサーバで定期的に走るプラグイン (batch-mode plugin) によって更新されています。
例えば web サーバの apache のログを集計して怪しい IP をリストアップするプラグインや、各種のサイト/api などから URL のブラックリスト/ホワイトリストを更新するプラグイン、スパムちゃんぷるー自身の過去の判定結果を基にベイジアンフィルタの再学習を行うプラグインなどがあります。

スパム送信元によっては dosアタックに近い頻度でコメント/TBを絨毯爆撃してくるところがあり、この攻撃をまともにうけると、ライブドアブログの 60台あるコメント/TB受け付け用のサーバ群でも太刀打ちできません。
こういったスパムについては、リクエストを modperl が受け付けるだけでも高負荷になるので、できるだけフロントのwebサーバ (リバースプロキシ) で弾いてしまいたい、という事情があります。
そこで、各サービスでこのリストをダウンロードし、例のように mod_rewrite の rewrite map file として指定し、アプリケーションサーバの手前でリジェクトする、という対策もしています。

ちなみに、ライブドアブログを使うと、アップロードした写真に簡単にモザイクをかけたり落書きしたりできます。新搭載のお絵描き機能、ぜひお試し下さい !
担当からのPRでした。

一応、発表の前日の5月13日〜14日にかけて、時間帯をわけて、ライブドアブログへのコメント/TBに対するスパムちゃんぷるーの判定結果1000件をランダムに抽出し、目視でそれらの判定結果と false positives (スパムでないものをスパムと誤判定した数)、 false negatives (スパムをスルーしてしまった数) を集計してみました。
1000件中、186件がスパムと判定され、内 false positve はみたところ 0 のようでした。ただし、スルーしてしまったスパムが 39〜59 件ほどありました。(スパムかそうでないかの判定が微妙なものもありますので、だいたいの数字です。)
これだけ見ると多少 false negatives (スルーしてしまうスパム) が多い印象もあるかもしれませんが、もともとこのスパムちゃんぷるーは数段階あるスパム防壁の最終段にあたります。
dos アタック防壁や、先に挙げた rewrite map file によるIP単位でのリジェクトによる、apache レベルでのフィルタリング
↓
グローバルのブラックリスト、投稿間隔チェック、送信先のブログの存在チェックや、ユーザによるNGワード設定チェックなど、アプリケーションレベルでのフィルタリング
↓
スパムちゃんぷるー
というように、多くの (比較的シンプルな手口の) スパムはスパムちゃんぷるーに入る前にリジェクトされているので、上記の数字には含まれません。(スライドにあるように、IPレベルでリジェクトされるリクエストが、一日で500万件を超える日もあります。)
以上が発表の概要です。
発表の後、思いのほか多くの方々から質問やご意見をいただきました。懇親会でも同様の取り組みをされている方々とお話させて頂く機会がありました。皆様ありがとうございました。
やはり、どこのサービスもおなじように孤軍奮闘されているのだなという印象を受けました。
性質上、情報を明らかにすることについ躊躇してしまう分野ですが、それゆえにスパム対策はどうしても孤独な闘いになりがちです。
深夜に、スパムコメントの絨毯爆撃にひとりで対応している時など、ふと、向こう側は何人いるんだろう、これはいったい何人対何人の闘いなんだろうか、と考えることがありますw
向こう側にいるのは、スパムビジネスのために組織化された集団かもしれませんし、もしかしたら、世界中の bot net をあやつるたったひとりのスーパーハカーなのかもしれません。
ただ分かっているのは、こちら側にも多数の味方がいるということです。それぞれが個別に闘うよりは手を組む方が良いに決まってますよね。
そういう観点から、スパムちゃんぷるーのソースや統計データなど、出来る限り情報はオープンにしていきたいと考えています。
プラグインを作る人がもっといたら精度あがるだろうなぁ、とか、ライブドアはなんといっても日本屈指のスパム受信者 (日本屈指の送信元でないことを祈る) なので、統計データを提供する意義はきっとあるだろうなぁとか、個人的にも色々と思うことはありまして、出来る範囲で進めていきたい考えですので、今後ともどうぞよろしくおねがいします。
なお、スパムちゃんぷるーのレシピが知りたい方は、こちらなどをご覧下さい。
