スパムボットのようなコンピュータプログラムと人間を区別するために、CAPTCHA と呼ばれる仕組みが使用されています。Google や Yahoo! など大手サイトでもこの仕組みを利用して、プログラムからの攻撃に対する防御力を高めています。
このエントリでは、この CAPTCHA のうち Gimpy と呼ばれる仕組みを使ったコメントスパムボットへの対策を紹介しています。
背景
CAPTCHA とは「コンピュータと人間を区別する完全に自動化された公開チューリングテスト」の接頭句で、例えば、複数枚の絵から連想される単語を答えると云ったような、人間には簡単に解ける問題でもコンピュータプログラムにはそれが難しい、という性質を利用したものです。
Google のサイトの登録ページで見られるものは、CAPTCHA のうちでも Gimpyと呼ばれる仕組みで、MovableType でもコメントスパムボット対策として、これを利用したプラグインがあります。
James Seng's blog:Solution for
comments spamsは、
コメントの投稿時にランダムな数字列の画像から認証キーを入力するもので、
小粋空間:
MT-SCode プラグインによるコメントスパム対策(その1)でその導入方法が詳細に解説されています。
ただ、この仕組みはコメントスパムボット以外のプログラムに対しても非常に効果的ではありますが、MovableType のプラグインという形態のために再利用しにくいと言えます。せっかくですから、MovableType 以外の環境や、更には普通のログインシーケンスなどにも流用できるようにしたいものです。
そこで、これをヒントに
MovableType 以外にも様々に流用できるような
Gimpy の廉価的実装を行いました。
仮にこれを Tiny
Gimpy と名付け、
MovableType などの環境に依存しないよう独立した
CGI として動作するようにしています。
以下にこの Tiny
Gimpy を
MovableType に導入する手順を紹介します。
今のところ非常に簡易的なモノなので Tiny ということで。
最新版のダウンロードやバグレポートはCAPTCHA の trac レポジトリでも行っています。
Step 0. 設置と動作確認
Tiny
Gimpy の本体である tgimpy.cgi は、チューリングテストのための画像生成
CGI と、
パスコードのチェック用ライブラリを一つのファイルで兼ね備えています。
tgimpy.cgi を
ブラウザから直接実行した場合、クエリ文字列と個別の設定ファイルから
一意の数字列を含む PNG 画像を生成・表示します。
動作には
サーバに以下の
Perl ライブラリがインストールされている必要があります。
とりあえず、tgimpy.cgi を
サーバにアスキーモードでアップロードし、
パーミッションを 755 または 777 に設定した後、
ブラウザから呼び出してみてください。
9 桁の数字列がランダムに表示されればひとまず成功です。
Step 1. パスの設定
設定ファイル(後述)の保存先に合わせて、tgimpy.cgi を修正します。
tgimpy.cgi をエディタで開き、
GetCfgPath を
サーバに合わせて修正してください。
設定ファイル(次のStep.2で説明)はここで指定したディレクトリパスに保存します。
Step 2. 設定ファイルの作成
アーカイブに添付の sample.cfg を好きな名前に変え(ここでは yourblog.cfg と仮定します)、
Step 1 で設定したディレクトリパスにアスキーモードでアップロードします。
個別エントリの
テンプレートを修正し、tgimpy.cgi への呼び出しと、
コメント投稿フォームに認証用のフィールドを追加します。
文字列"yourblog"を任意に変更した場合は、全ての箇所を同じにしてください。
(MT のインストールパス)/lib/MT/App/Comment.pm を修正します。
CheckAnswer 関数が用意されているので、
これを使って入力された認証キーが正しいか否かを判定し、
不正な場合はエラーメッセージを表示します。
設定ファイル(*.cfg)について
設定ファイルでは、T
Gimpy の動作について幾つかの項目を
カスタマイズすることができます。
- szCryptKey
-
秘密キーです。
tgimpy.cgi の結果は公開キー(エントリ ID)と秘密キーから計算しています。
この秘密キーの存在が、スパムボットの作成を困難にしています。
できるだけ長く、推測されにくい文字列を与えます。
- nSizeX, nSizeY
-
tgimpy.cgi 呼び出し時に作成される認証用画像のサイズをピクセル単位で指定します。
- nFigure
-
認証用キーのケタ数を 1 から 9 の間で指定します。
トラブルシューティング - 動かない時は?
-
症状:画像が表示されない
症状:tgimpy.cgi を直接呼び出すと Internal Server Error になる
-
原因:CGI の準備に何らかの問題があります
対策:tgimpy.cgi がアスキーモードで FTP 転送されているか確認してください
対策:tgimpy.cgi のパーミッションが 755 または 777 に設定されているか確認してください
対策:tgimpy.cgi の 1 行目 #!/usr/bin/perl の部分をお使いのサーバの Perl に合わせて変更してください
対策:サーバに必要な Perl モジュールがインストールされているか確認してください → Step.0
対策:GetCfgPath を修正した個所に余計なシングルクォーテーションや全角空白がないか確認してください → Step.1
対策:設定ファイルがアスキーモードで FTP 転送されているか確認してください
対策:設定ファイルの修正した個所に余計なシングルクォーテーションや全角空白がないか確認してください → Step.2
-
症状:tgimpy.cgi?cfg=yourblog&key=1 として直接実行した時、設定ファイルの nFigure で指定したケタ数で表示されない
症状:tgimpy.cgi?cfg=yourblog&key=1 として直接実行した時、設定ファイルの nSizeX, nSizeY で指定したサイズで表示されない
-
原因:設定ファイルが正しく読み込めていません
対策:GetCfgPath が正しく設定されているか確認してください → Step.1
対策:設定ファイルが正しく配置されているか確認してください → Step.2
対策:cfg=... で指定された文字列が設定ファイルと同じか確認してください → Step.2
-
症状:コメントを投稿すると Internal Server Error になる
-
原因:MovableType への修正箇所に問題があります
対策:MovableType(Comment.pm) の修正箇所が正しいか確認してください → Step.3-2
対策:MovableType(Comment.pm) の修正箇所に余計なシングルクォーテーションや全角空白がないか確認してください → Step.3-2
対策:MovableType(Comment.pm) の require '...' の行が、正しく tgimpy.cgi を指しているか確認してください → Step.3-2
-
症状:コメントを投稿しても必ず拒否される
-
原因:必要なパラメータが CGI に正しく渡っていません
対策:コメント投稿フォームに cfg フィールドがあるか確認してください → Step.3-1
対策:コメント投稿フォームの cfg フィールドの値が設定ファイルと同じか確認してください → Step.3-1
対策:コメント投稿フォームの ans フィールドがあるか確認してください → Step.3-1
対策:img タグの tgimpy.cgi の呼び出しパラメータである cfg と key の値が正しいか確認してください → Step.3-1
対策:ans を半角数字で入力されているか確認してください
既知の問題
- コメントを直接投稿する場合の動作確認はありますが、事前にコメントのプレビューをした場合、
Tiny Gimpy に必要なパラメータを渡せません。
- TypeKey 認証との併用は未検証です。
そしてボットは居なくなった
この例では、キーとして MTEntryID を用いて tgimpy.cgi を呼び出しているため、
一つの記事に対していつでも同じパスコードが生成されています。
そのために、スパマーがこのパスコードを見た上でスパムボットを調整してやると、
そのスパムボットはその一つの記事に対してコメントすることが可能になってしまいます。
しかし、もしスパムボットを他の記事にもコメントを投稿できるようにするならば、
スパマーはこの手順を同じ数だけ繰返さなければなりません。
(この手順を自動化すること自体が CAPTCHA によって不可能に近い)
そして管理者が秘密キーを 1 つ変えてしまうだけで、その苦労は全て無駄になってしまいます。
そんなことならば、わざわざスパムボットを使ってコメントを投稿するよりも、
人間が手動で直接にコメントを投稿して回った方が早いということになるわけです。
しかし、それは既に"スパムボット対策"ではなく、単なる"人間によるコメント荒らし対策"に他ならないのです。
この記事を読んだ人はこんな記事も読んでいます
MovableType, NovableType, JovableType, KovableType, MIvableType, M9vableType, M0vableType, MPvableType, MLvableType, MKvableType, MoCableType, MoFableType, MoGableType, MoBableType, MovQbleType, MovWbleType, MovSbleType, MovZbleType, MovaVleType, MovaGleType, MovaHleType, MovaNleType, MovabKeType, MovabOeType, MovabPeType, MovablWType, Movabl3Type, MovablRType, MovablDType, MovablSType, MovableRype, Movable5ype, Movable6ype, MovableYype, MovableGype, MovableFype, MovableTTpe, MovableT6pe, MovableT7pe, MovableTUpe, MovableTHpe, MovableTGpe, MovableTyOe, MovableTy0e, MovableTy-e, MovableTyLe, MovableTypW, MovableTyp3, MovableTypR, MovableTypD, MovableTypS
スパム
CAPTCHA, XAPTCHA, DAPTCHA, FAPTCHA, VAPTCHA, CQPTCHA, CWPTCHA, CSPTCHA, CZPTCHA, CAOTCHA, CA0TCHA, CA-TCHA, CALTCHA, CAPRCHA, CAP5CHA, CAP6CHA, CAPYCHA, CAPGCHA, CAPFCHA, CAPTXHA, CAPTDHA, CAPTFHA, CAPTVHA, CAPTCGA, CAPTCYA, CAPTCUA, CAPTCJA, CAPTCNA, CAPTCBA, CAPTCHQ, CAPTCHW, CAPTCHS, CAPTCHZ
CGI, XGI, DGI, FGI, VGI, CFI, CTI, CYI, CHI, CBI, CVI, CGU, CG8, CG9, CGO, CGK, CGJ
Perl, Oerl, 0erl, -erl, Lerl, PWrl, P3rl, PRrl, PDrl, PSrl, PeEl, Pe4l, Pe5l, PeTl, PeFl, PeDl, PerK, PerO, PerP
Gimpy, Fimpy, Timpy, Yimpy, Himpy, Bimpy, Vimpy, GUmpy, G8mpy, G9mpy, GOmpy, GKmpy, GJmpy, GiNpy, GiJpy, GiKpy, GimOy, Gim0y, Gim-y, GimLy, GimpT, Gimp6, Gimp7, GimpU, GimpH, GimpG
寄せられたコメント (全 8 件中、最新 5 件まで表示しています)
今までのスパムは何だったんだ?というくらい効果覿面。10日以上経っていますが、未だゼロ。
もっとも、普通のコメントも滅多になんですけどね(笑)
次はMT4化をしたいところですが、サーバが非力なせいか、Out of memoryになっちゃうんですよね。
自宅で公開サーバを立てればいいんですけど、それはそれでセキュリティ対策に
腐心しなくてはならなくて。セキュリティ対策するためにサーバ立てるんじゃないぞと^^;;
> 万人向けとはいきませんね、確かに。
まぁ現状で万人向けか?って言われるとそれも疑問なんですけれど、
やはりHTML+テンプレートタグ程度で編集できるのが簡単と思いますね。
> 要はエントリーIDの代わりにハッシュ値を使う点
このハッシュ値を毎回ランダムにすれば、表示される数値は毎回変わりますね。
ただ、そのハッシュが一度きりの使い捨てであることを確実にする仕組みも作らないと
結局今のエントリIDを固定で使っている場合と実質は何も変わらないんですよね…
# うーん、説明下手でスミマセン
それでも毎回同じというのは見た目的に弱そうなので(笑)改善の余地はあると思いました。
レイアウトの問題は確かにあります。慎重に要素にidを振っておいてCSSで制御するとか、必要な情報をJSONで渡して適当にJavascriptを使ってレンダリングするとか方法はありますが、万人向けとはいきませんね、確かに。
アルゴリズムの方はあまり難しくない感じがしています。例えば、時刻からランダムな文字列を作り、それをMD5でハッシュ化します。次に文字列に対応する画像を作り、ハッシュ値+拡張子という名前にしておきます。すると、CAPTCHA用のフォームはハッシュ値だけを使って作れます。
要はエントリーIDの代わりにハッシュ値を使う点以外はほとんどぴろりさんの方法で行けると思います。
> これらを出力するJavascriptをCGIが返すようにする
フィールドや画像を埋め込む手間を省けると云う点では一理ありますね。
ただ、フィールドや画像のレイアウトを変更したいと思った時に、
テンプレート(実質は HTML)ではなくJavaScripを編集してレイアウト変更するというのは、
多くのユーザにとって敷居が高くなるかな?とも思います。
> 表示ごとにCAPTCHAコードを変えることができる
本当なら堅牢性の面からもこれは目指したいところなんですが…
ページごとに異なる隠しキーをどうやって扱うのか、という所で良い解決策が見えていません。
一応『ショボいけど導入の手間が掛からない』のバランスで言えば、今もアリかなと(笑
ちょっと思ったのですが、img要素とinput要素をテンプレートに書くのではなく、
これらを出力するJavascriptをCGIが返すようにするとよいのではないでしょうか。
そうすれば表示ごとにCAPTCHAコードを変えることができると思います。