迷惑投稿対策 2017年03月03日 21:03   編集
掲示板の迷惑投稿を防ぐ方法としては、ロボットではなく人が投稿していることを確かめるため、ロボットには読めないはずの画像による文字を読ませて入力させたり、複数の画像から質問に該当するものを選択させたり、掲示板に投稿する利用者に一手間かけさせるものが多い。
ここでは、なるべくユーザーに余計な手間をかけさせず、スパムを防止する有効な方法がないものか考えていきたいと思う。

投稿ID方式

フォームに隠しパラメータを仕込んでおいて、その値を送ってこない投稿は不正投稿としてブロックするという対策法は昔からある。しかしフォームのhtmlを解析しているのか、正しい隠しパラメータを送信してブロックを回避するスパム投稿は多いので、これだけではあまり効果のある対策とはいえない。フォーム表示のたびにランダムな値に変更しても同様だ。
しかし、最近これに投稿までの時間を計測して、あまりに早いものはスパムとして判断してブロックするという対策がどこかで紹介されていた。
なるほど、ロボットによるスパム投稿は大量の投稿をこなしたいはずなので、普通に人間が投稿するようにフォームを表示させ、名前やコメントをキーボードから打ち込んで投稿ボタンを押しているということはまず考えられない。フォームを表示しないかもしれず、したとしてもすぐに投稿しているとしたら時間計測によるブロックはけっこう効果があるかもしれない。処理としては、以下のようになる。

拒否処理

  1. 投稿フォーム表示する際、投稿IDを生成する。投稿IDはランダムな文字列で、input hiddenタグに投稿IDを表示し、同時に投稿IDが名前のファイルをサーバーに作成する。
    ファイルを開かなくても投稿IDが確認できるよう、テキストファイルに投稿IDを書き込むのではなく、ファイル名そのものを投稿IDにする。
  2. 投稿受付処理では隠しパラメータから送られた投稿IDに相当するファイルがサーバーに存在しなければ投稿をブロックすることになる。
    また、ファイルの生成時間が新し過ぎる場合もブロックする。stat関数でファイルの作成時間を取得し、現在時間との差がたとえば10秒以下のものはブロックする。
  3. 投稿を受け付ける場合、投稿IDファイルは削除する。拒否する場合も削除すると、慌てて投稿した正規のユーザーが投稿フォームに戻って再度投稿できなくなるので、削除しないことにする。
投稿IDファイルは投稿フォームを表示しないと生成されない。このためフォームを介さず直接投稿用パラメータを送ってくるようなロボットは、該当する投稿IDファイルが存在しないのでその時点でブロックされる。(しかし拒否ログを見てみると、投稿IDを送ってこなかったり、投稿IDの該当ファイルが存在しないというケースは少ない。やはりHTMLでフォームのinput要素を調べてから投稿しているようだ。)
HTMLを解析して隠しタグの投稿IDを取得してから投稿してきても、それが早すぎるとブロックすることになる。
正規の利用者が通常の投稿をする場合、フォームを表示してから、投稿内容を入力して送信ボタンを押すまでは少なくとも数10秒はかかるだろうから、あまり早すぎるもの(たとえば10秒以下)は人間が投稿したものではないと判断することになる。
スパム側の対策として、フォームを表示させてからタイムラグをおいて投稿させることは技術的には難しくはないだろうが、効率よく大量のスパム投稿をしたいロボット側としては、あまりやりたくないと思う。投稿時間ではじかれることがわかったら、タイムラグを作って効率を下げてでも投稿するよりは、もっと効率的に投稿できる他の掲示板を探すのではないだろうか。

ダミーフィールド方式

ネット上を調べるとWord PressのThrows SPAM Awayというプラグインがけっこうスパム防止効果が高いらしい。
以下のような項目をチェックして該当するとブロックするということだ。
  1. 日本語を含んでいない
  2. NGワードが含まれる
  3. リンクが含まれる
  4. ダミーフィールドに入力があった場合(ロボット対策)
  5. IPアドレス一致
  6. 外部提供のスパムリストに一致
1、2、3、5は多くの掲示板プログラムで採用されている対策で特に目新しい方法ではない。
気になったのは4のダミーフィールドに入力があった場合(ロボット対策)という項目。
これは入力してはダメというフィールドを作っておいて、それに入力があったらロボットと判断して拒否するということのようだ。それが効果があるということは、スパム投稿用のロボットというのは、フォームのinput要素すべてに、なんか入れて送るという習性があるのかもしれない。
そういえば入力が任意のフィールドにもすべて何か文字列を入れて投稿しているスパムが多いような気がする。必須フィールドの入力がないために投稿が拒否されることを避けるためだろうか。
これも試す価値がありそうだ。
フォームに実装する場合、「ここには入力しないでください」と書いたテキスト入力フィールドを作るか、あるいはスタイル指定で通常のユーザーは認識されないようなフィールドにしてもいいかも知れない。
ロボットはHTMLコードを読んでいるようなので、そのようなフィールドでもしっかり見つけて入力してくるに違いない。たとえば以下のフォームでは、
 
コメント  
コメントの右はcommentというパラメータ名のtextフィールドだが、これだけでなくこの右にはiamrobotというパラメータの入力フィールドがあるのだが、スタイル指定で非表示になっている。
通常の投稿者はこのiamrobotフィールドには入力しない(というかできない)が、ロボットはここにもなにか書き込んで送信してくる可能性がある。ロボットはHTMLコードを解析していると考えられるからだ。
試してみると、案の定見えないフィールドからも値を送ってきた。効果を期待できそうだ。

実験結果

スパム対策研究用掲示板に投稿ID、ダミーフィールド2つのスパム投稿防止処理を入れてみた。
この掲示板では、フォーム内にパラメータ名が「robot」というダミーのテキストフィールドを追加し、スタイル指定でvisibility:hiddenとして表示されないようにしている。また、フォームを表示するたびにランダムな文字列を生成して投稿IDとし、input hiddenタグに表示するとともに投稿ID名のファイルをサーバーに作成している。

通常の掲示板では、複数のスパム対策処理を行う場合、どれかひとつに引っかかればその時点で処理を中止し拒否するが、この実験用掲示板の場合、どのスパム対策が効果があったのか拒否ログに記録するため、すべてのスパム対策処理を行う。もちろんどれかに引っかかれば最終的には投稿拒否する。これによって各スパム投稿に対してどの対策が効果があるのか分析することができる。拒否ログ閲覧もCGIで行う。
ログを見ると、大量のスパム投稿をブロックしているのがわかる。3種類のタイプがある。
一番多いのが投稿者名、タイトルがひらがなになっていスパムで、これはダミーフィールド、投稿IDの時間チェックどれにも引っかかる。ときどき投稿キーで引っかかることもある。数は多いが、ダミーフィールドから送ってくるのでほぼ確実にブロックできる。

次に本文が英語で投稿者名、タイトルがランダムな英文字になっているスパム。これもダミーフィールド、投稿IDの時間チェックどちらにも引っかかる。投稿キーに引っかかることはないが、ダミーフィールドから送ってくる以上確実にブロックできる。

やっかいなのはタイトルが6ケタの数字になっているスパムで、これはダミーフィールドに引っかからない。投稿キーもスルーするので、なんとか投稿IDの時間チェックでブロックしている状態だ。サーバーが重くなっていたりすると投稿されてしまうおそれがある。

ところで投稿者に入力の手間をかける投稿キーは、残念ながら思ったより効果がないようだ。

eメール入力フィールドを隠す

ほとんどのスパム投稿はeメールアドレスを投稿してくる。
name属性が「robot」のダミーフィールドには引っかからなかったスパム投稿も、eメールアドレス入力欄がダミーになったら送ってくるのではないかと期待して、eメール入力フィールドをスタイル指定の display:none で隠してみた。
すると不思議なことに、スパム投稿がピタッとなくなった。拒否されたログにも記録されなくなった。

これはどう解釈すればいいのだろうか。
eメール入力フィールドを表示しなくなったことによって、ロボットはeメール入力欄がなくなったと思い、eメール入力欄のないフォームには投稿しないというプログラムになっているのか。それともフィールドにdisplay:noneが指定してあればあきらめる設定になっているのか。ちなみにrobotフィールドの方は display:none ではなく visibilty:hidden で隠している。
たまたまスパム投稿が一区切りついたところというだけかもしれないので、とりあえずeメール入力欄を元に戻して様子を見てみる。
eメール入力欄を元に戻したが、明らかに投稿件数が減っている。数分に1回あったひらがなタイトルの投稿がなくなった。eメール入力欄とは関係ないのかもしれない。再度eメール入力欄を非表示にして様子を見ることにする。

スパム投稿が減ると調査はやりにくくなるが、実際に掲示板を設置した場合、ブロックすべき投稿がガンガン来て片っ端から拒否するよりも、最初からそんな投稿がない方がもちろんいい。
テキストフィールドを非表示にするスタイル指定があるフォームは最初から投稿はしないという設定になっているのか?
もしそうなら、CGIにも負担をかけずに済むので、効果的な対策ということになる。
そんなうまい話があるのかと思ったが、その可能性はありそうだ。以下の理由からだ。
投稿IDによる処理では、フォームを表示した時点で投稿IDファイルを作成する。FTPソフトでこの投稿IDファイルを調べると、ブロックしたスパム投稿がない場合もこの投稿IDファイルが次々と作成されていることがわかった。これはフォームだけ表示してみたが、なんか罠が仕掛けられてそうで、うまくいきそうもないので諦めて帰ったという動作を裏付けるものではないか。
投稿IDファイル作成のログも取り、分析してみた。
拒否された投稿以外にもかなりアクセスがあることがわかる。リンク元がなかったり、通常のユーザーのアクセスではあり得ないリンク元になっているケースが多い。通常のユーザーのアクセスがこんなにあるとは思えないので、ほとんどがスパムではないかと思う。しかし、このうち実際に投稿して拒否されるのは一部だ。やはりフォームまで来て何もせずに帰るロボットがいるようだ。
投稿もせずにあきらめるというのもずいぶん弱気なスパムだという気もするが、限られた時間でより大量に投稿する効率を考えると理解できる行動だ。しかしフィールドが隠されているとわかっているなら、そこは値を入れずに投稿することもできると思うのだが。
いずれにしてもこれが有効なら、最初から使わないテキストフィールドを非表示にする記述を追加するだけでスパム防止の効果があるということになるが、もう少し調べないとわからない。

ところでダミーフィールドに引っかからなかった数字タイトルのスパムだが、やはりeメール入力欄を非表示にしてもメールアドレスを送ってくることがわかった。ということはこのメールアドレスを送ってくる投稿も拒否するようにすれば、ブロックできるはずだ。
ダミーのeメールフィールドの入力を拒否するようにしたら、これまで投稿キー、投稿ID、ダミーのrobotフィールドいずれもすり抜けてきたスパムのブロックにやっと成功した。
eメール入力欄でブロック

この掲示板へのこれまでのスパム投稿はすべてメールアドレスを送ってきている。ということはこのメールアドレス送信分をブロックすればほぼすべてのスパム投稿に対応できることになる。
ただし、HTML内のスタイル指定を解析し、input要素を隠す設定になっていたら何らかの対策を行うことになっていれば別だ。スパムはスタイルまでは解析しないというのが、これまでの定説らしいが、この掲示板の拒否ログを見ただけでもdisplay:none;スタイルに反応しているような気配があるので、今後どうなるかわからない。

ダミーフィールドに対するスパムの挙動

しかし同じ非表示のフィールドなのに、送ってくる場合と送ってこない場合があることになるが、何が違うのだろう。ロボットは何を基準に判断しているのだろう。
まずフィールドのname属性が「email」か「robot」かの違いがある。一応name属性も考えているのだろうか。「robot」という名前はさすがに警戒されているかもしれない。すでに非表示フィールドによる拒否を行う掲示板でフィールド名に「robot」がけっこう使われているので、要注意名になっているとか。
非表示にするスタイルが「visibility:hidden」か「display:none;」という違いもある。
スタイルについては、そのほかinputタグに直接スタイルを指定しているか、inputタグを含むタグにしているかの違いもある。
このあたりも調査が必要かもしれないが、現在のデータでは
  1. ダミーフィールドの名前は通常inputタグで使うようなname属性にしておいた方が無難。
  2. 非表示にするの方法は「display:none;」がいい。
  3. 非表示にするスタイルシートはinputタグに直接ではなく、上位のタグに指定する方がいい。
ということがいえる。

eメールを入力させて表示すると、それこそスパムメールに狙われることになるので、当サイトの掲示板はeメール入力を求めないものが多い。入力してもメールアドレスは表示せず、CGIによるメールフォームでメールを送信してもらうことにしている。
なので、eメール入力欄は非表示にしても構わないのだが、やはりメールアドレスを入力して欲しいという場合は、name属性を「email1」などとダミーフィールドとは別にして通常の入力フィールドを表示すれば問題ない。
あるいはダミーフィールド名は「name」や「title」などname属性としてよく使われそうな名前にしてもいいだろう。本物の投稿者名やタイトル入力欄は「name_」や「title_true」などにするとか。
counter:7,244