sudofox's journal

Austin Burk's journal, where I share little snippets of my writing, code, and dreams.

はてなハイクスパム対策

In English: Hatena Haiku Anti-Spam - austinburk's blog

f:id:austinburk:20181204055910p:plain

はてなハイクスパム対策というサービスを開発しました。半年にわたる広範囲なテストにより、高い精度が実現されています。

背景

はてなにはスパムの問題があります。それも小さいものではありません。その影響ははてなが提供するほとんどのサービスに及び、特に目立つのは、ハイク、ブックマーク、ブログ、匿名ダイアリー、人力検索などです。フォトライフにもスパムの問題がありますが、私が調査しているものとは種類が異なります。

対策として、小規模な緩和策(ハイクなど一部のサービスの最初のエントリの障壁として人間性クイズを使用するなど)が試みられていますが、古いアカウントは適用の対象外となっています。これに関して、動作の一貫性が欠けているために、ユーザーが3回以上正解しても検証に成功しない場合があることを発見しました。

 

ハイクその他のサービスに投稿されるスパムは性質が非常に一貫しています。私は現在Webホスティング管理の会社に勤務し、ベイズフィルターと、Apache SpamAssassinという正規表現ベースのフィルタリングエンジンの組み合わせに関する経験があります。そこで、SpamAssassinにはてなハイクの投稿のフィルタリング機能を付け加え、より快適にサービスを使用できるようにしようと思い立ちました。

Eメールからのハイク

主に問題となったのは、SpamAssassinがEメールのフィルタリングに特化して設計されていること、つまり、Eメールメッセージのようなフォーマットの入力が想定されていることでした。

 

例(オリジナルの投稿):

Delivered-To: site@h.hatena.ne.jp
Received: by sudofox.spam.filter.lightni.ng (Sudofix)
        id 81807923680507219; Fri, 08 Jun 2018 09:12:22 -0400 (EDT)
From: austinburk@h.hatena.ne.jp (Sudofox)
To: site@h.hatena.ne.jp
Subject: 食べた
Content-Type: text/plain; charset=UTF-8
Message-Id: <20180908091222.81807923680507219@sudofox.spam.filter.lightni.ng>
X-Hatena-Fan-Count:212
Date:Fri, 08 Jun 2018 09:12:22 -0400 (EDT)

食べた=That looks AMAZING QoQ 

 

ヘッダーには、spamd (SpamAssassinのバックグラウンドで実行されるサービス)の解析の対象となる最小限の内容と、X-Hatena-Fan-Countが含まれています。

SpamAssassinのuser_prefsとカスタムルール 

ここにuser_prefsファイルがあります。"Begin Sudofox config"の後をご覧になるとわかるとおり、Eメール関連のすべてのチェック(たとえばSPF、RBL、DKIM)を無効化するなどの変更をルールに加えて、ハイクからのメッセージのフィルタリングへの適合性を高めています。それ以外に、ハイクのプライマリユーザーベースにより適合させるための変更("Begin Sudofox config"の上にありますが注釈はしていません)も加えています。 

また、ハイクに特有のSEOスパム(スポーツやテレビ番組の無料視聴に関連することが多い)に対処するために開発したルールもいくつかあります。 

スパムユーザーにはファンがいないことがほとんどであるため、このことをメトリックとしてフィルタリングに使用できます。それがX-Hatena-Fan-Countの用途です。 

header		SUDO_HATENA_ZERO_FANS X-Hatena-Fan-Count =~ /^0$/
score		SUDO_HATENA_ZERO_FANS 1.0
describe	SUDO_HATENA_ZERO_FANS User has no fans

header		SUDO_HATENA_FEW_FANS X-Hatena-Fan-Count =~ /^([1-9]{1})$/
score		SUDO_HATENA_FEW_FANS -1.0
describe	SUDO_HATENA_FEW_FANS User has 1-9 fans - spam less likely

header		SUDO_HATENA_10_PLUS_FANS X-Hatena-Fan-Count =~ /^([0-9]{2})$/
score		SUDO_HATENA_10_PLUS_FANS -2.0
describe	SUDO_HATENA_10_PLUS_FANS User has 10-99 fans - spam unlikely

header		SUDO_HATENA_100_PLUS_FANS X-Hatena-Fan-Count =~ /^([0-9]{3,})$/
score		SUDO_HATENA_100_PLUS_FANS -10.0
describe	SUDO_HATENA_100_PLUS_FANS User has 100+ fans - prob legitimate

 スパムの作成者が私のブログの投稿を読んで適応したとしても、実際のスパムのコンテンツのスコアは通常は高いため、互いをファンとして追加することで2ポイントがマイナスされてもなお、スパムとして認識できると考えています。 

ソースコードはこちらです。実験的に開始したため、若干未整理です。しかし、はてなユーザーが実際に(APIやユーザースクリプト経由で)使用するサービスに成長したため、近いうちに全体を書き直す予定です。

 

このリポジトリには、スパム分類コードとspamdに関連する内容のみが含まれています。 

Webサイト

はてなハイクスパム対策には、ブラウズできる2つのセクションとして、メインの概要ページとユーザー情報ページがあります。

f:id:austinburk:20181018104837p:plain

メインページには2つの円グラフがあり、左のものは最近のスパムユーザーを示し、右のものは最近の正当な投稿を示します。表示対象の期間は24時間で、円グラフの任意のスライスをクリックすると、ユーザー情報ページが表示されます。

 

ユーザー情報ページには、そのユーザーの全体的なスコアのグラフが以下のように表示されます。

 

f:id:austinburk:20181018105115p:plain

また、ここには、10投稿のサンプルと、それらがどのように分類されているかが示されます。実際のスパムコンテンツを再びパブリッシュすることがないよう、採取したテキストのサンプルはbase64エンコードのスニペットとして保存し、HTMLキャンバスにレンダリングすることで表示できるようにしています。

最近の例です(最近はドラッグ関連のスパムが増えており、このような内容のフィルタリングは比較的簡単です)。

f:id:austinburk:20181018105225p:plain

正当なメッセージの例です。

f:id:austinburk:20181018105623p:plain

API

はてなハイクスパム対策のAPIを提供しています。

スパムのフィルタリングに最もよく使用するものは、最近のスコアのAPIです。

https://haikuantispam.lightni.ng/api/recent_scores.json

これにより、最近投稿しているはてなIDと、そのスコアが示されます。スコアが5を超えるとスパムと見なされます。

こちらは最近のキーワードのAPIです。

https://haikuantispam.lightni.ng/api/recent_keywords.json

ハイクのキーワードの性質上、特定のキーワードに善悪のラベルを付けることは簡単ではありません。ここでのスコアは、各キーワードに対する投稿の最近のスコアの平均を使用して得られます。それでも、ページの右側にあるキーワードリストを更新することは有益です。

ユーザースクリプト

id:noromanba氏が、最近のスコアのAPIを利用して、はてなハイクをブラウズするときにスパムをフィルタリングする優れたユーザースクリプトを開発されました。インストールすることをお勧めします。

(TampermonkeyViolentmonkeyまたはGreasemonkeyで使用できます。私個人では、すべての最新のブラウザーとの互換性を備えた、Tampermonkeyを使用しています)。

ページの上部に、スクリプトへのリンクがあります。

f:id:austinburk:20181018111344p:plain

次のリンクから直接アクセスできます。

https://gist.github.com/noromanba/e485c35ffba606ae8ecacac2c9a8da3c/raw/hatenahaiku-spam-filter.user.js

Slack用のリッチコンテンツタグ

この機能の用途は限られていますが、ハイクスパム対策のリンクを付けてユーザーをはてなに報告するたびに、Slackbotからのヒットが発生している(つまりはてなでSlackが使用されている)ことに気付きました。このため、ハイクスパム対策によって分類されるユーザーの概要を示すタグを追加しました。

f:id:austinburk:20181018104347p:plain

今後

さまざまな自分のプロジェクトの管理が多忙にしていますが、ハイクスパム対策の保守と改善は必ず続けます。私の真の願いは、はてなと協力して、同社のサービスのための正確でスケーラブルなスパム検出システムを開発すること、あるいは、最小限、その実現方法のアイデアと例を提供することです。

はてなハイクスパム対策に対しては、次のことを近日中に更新するつもりです。

- 分類に使用する投稿の格納方法

- データベース: 現在は、ポータブルであるためSQLiteを使用していますが、時間の経過に伴い、適切にスケーリングできなくなる可能性があります。ハイクスパム対策にはすでに時折タイムラグが見られます(APIでは結果をキャッシュし、ユーザーのリクエストとは独立して更新を実行するため、タイムラグは発生しません)。アプリケーションをMySQLに移行することを計画しています。

- ハイクスパム対策バックエンドとサイトマージ: 現在、GitHub上のコードはバックエンド向けのもののみとなり、サイトのフロントエンド向けのものはありません。MySQLへの移行が完了し、サービスに関与するファイルへの直接アクセスや直接のパスを除去したら、Webサイトの部分もGitHubに配置することを計画しています。

 

Thank you to id:PlumAdmin for the translation of the original article. I am very grateful.

読者になる,くださいか?