ReadMe!等の「アイコンが表示された回数をカウントするランキングサイト」における不正投票の方法について。
ReadMe!に関しては「今後もネットを続ける限り『いつかReadMe!で天下とったる』と思い続けるだろう」と思うので実験はしていません。ただ「実験するまでもなく確実にこの方法で不正投票ができる」という確信はあります。もしこの方法を実際に試す方いたらこっそりメールで結果教えて下さい。「うまくいかなかった」という方は特にお願いします。報告してもらえればReadMe!内部システムが少し見えるかもしれなくて対応策もあるかもしれないので。
「何故この方法で不正投票ができるのか」「この方法にはどの程度安全性があるのか」といった話は後で書きます。まず先に具体的方法を。
「プロキシリストに登録したリスト内のプロキシを一定時間間隔で切り替え」という機能があります。この機能が今回のミソです。
「設定」「BugBrowserの設定」「プロキシリスト」でその「切り替えるプロキシのリスト」を編集できます。
BugBrowserと同じフォルダの「BugWeb_Proxy.dat」がプロキシリストファイルです。既に入手しているリストをこのファイルにコピーする方がGUIで一つ一つ登録するより圧倒的に簡単でしょう。
「ランダム切り替え間隔」に分数を指定するわけですね。とりあえず1分で。
<html>
<meta http-equiv="refresh" content="40;url=自分自身">
<frameset cols="100%,*">
<frame src="サイトのURL">
<frame>
</frameset>
</html>
このHTMLファイルのファイル名を「autoreload.html」にしたなら「自分自身」は「autoreload.html」です。「サイトのURL」にはReadMe!アイコンがあるページのURLを。「http://www.tokix.net/」とか。ネット上のモノを指定。
大事なのはこのHTMLファイルをローカルで使うってことです。アップしてはダメです。
「インターネットオプション」「インターネット一時ファイル」の「設定」を「ページを表示するごとに確認する」にします。
BugBrowserが「プロキシサーバーをランダム選択で使う」になっていることを確認して2のファイルを開きましょう。アドレスは「C:\My Documents\autoreload.html」とかになっているはずです。
開いたら放置。引きこもってないで外に出ましょう。
これで終わりです。帰ってきたらReadMe!の投票結果発表を待ちましょう。
ReadMe!不正投票マニュアル(1)では「それをすると何が起こるのか」というのを一切書かずに具体的方法のみを記述したので、今回は「何が起きているのか」というメカニズム解説を。
ReadMe!は「カウント用アイコンが表示された回数でランキング」というシステムです。
<img src="http://readmej.com/readme.cgi?webmaster@tokix.net">
こんな具合にimgタグを使ってカウンタ用アイコン表示CGIを呼び出す訳です。
この「カウンタ用アイコンCGI」とはつまり「投票処理を行いアイコンを出力する」というモノなのですね。問題はこの「投票処理」です。CGIの「処理」は外部から見えません。出力結果(この場合ならアイコン)しか見えません。なので我々のような「ReadMe!スタッフでない人間」は「どのような処理が行われているか」という疑問には推測でしか答えられない訳です。ブラックボックス。
話が逸れていることに気付きつつ書くなら、ブラックボックスの中身を知るには正統的知識(例えばCGIを自分で組んだりした経験則)と実験結果を使うしかありません。逆の言い方をすれば正統的知識はいつも「ブラックボックスへのちょっとした好奇心」に向かい「イタズラの計画」に向かう(カッコつけてみました)。
何度再読込(リロード)されても1回しか集計しません
たまに「順位を上げたいのでリロードしてください」と書かれているページを見かけますが、これは勘違いをされています。ReadMe!では、同じ人が一日のうちに何度アクセスしても1票しかカウントしません(翌日になったら、また1票カウントします)。
この説明は具体的にはこういうことです。
同じIPアドレスからの投票は一日一票まで
もちろん「100%そうなの?」と言われたら「知るか」としか返せません。「ブラックボックス」ですから。
「プロキシ」というものに対するよくある見解。
プロキシは「見かけのIPアドレスを一番手軽に変更する手段」です。とりあえずそれは間違いありません。
同じIPアドレスからの投票は一日一票まで
プロキシを使えば見かけのIPアドレスが変わります。ReadMe!不正投票マニュアル(1)の不正投票はそれを利用している訳です。もちろん手動でプロキシ設定を切り替えて再読込を押したっていいです。ただ普通に配布されているツールを使えば機械任せでできるんだ、と。
以下補足。
「同じPCから」ってのはCookieを利用します。ユーザーのPCにCookieデータを仕込みそのデータを根拠にする訳ですがReadMe!はCookieを使用していません。それは推測でなく事実です。ブラウザを「Cookieを受け入れる際にダイアログを表示する」という設定にすれば確認できます。
そして「同じ回線から」という判断はIPアドレスを根拠に行われます。
もちろん、第三の方法を使っている確率が0%な訳ではありません。それが「CGIはブラックボックスだ」ということであり「知識と実験で推測することしかできない」ということです。
最後に安全性に関して。
何度も書きますがCGIはブラックボックスです。「投票処理」には当然「不正投票を防止する」というルーチンが組み込まれているはずですが外部からそれは見えません。
とりあえず「どのような問題点が考えられるのか」というのをピックアップしてみます。外部から処理が見えない以上、「〜考えられるのか」を考えることしか僕らには出来ない。
投票処理には「プロキシからの投票を無効化」といった制限がかかっているかもしれません。さて、この「プロキシからの」なんですが、CGI単体で「プロキシからか生か」を断言する方法はこの世にありません。ある有名な掲示板スクリプトの「アクセスがプロキシ経由か判断するルーチン」を書いておきます。
if($ENV{'HTTP_VIA'} ne "" ){$use_proxy = 1;}
「ne」は「not equal」。いわゆる「プロキシ特有の環境変数」の参照。
if($ENV{'HTTP_X_FORWARDED_FOR'} ne ""){$use_proxy = 1;}
if($ENV{'HTTP_FORWARDED'} ne ""){$use_proxy = 1;}
if($ENV{'HTTP_X_LOCKING'} ne ""){$use_proxy = 1;}
if($ENV{'HTTP_CACHE_INFO'} ne ""){$use_proxy = 1;}
if($ENV{'HTTP_CACHE_CONTROL'} ne ""){$use_proxy = 1;}
if($ENV{'HTTP_SP_HOST'} ne ""){$use_proxy = 1;}
if($ENV{'HTTP_FROM'} ne ""){$use_proxy = 1;}
if($ENV{'HTTP_PROXY_CONNECTION'} ne ""){$use_proxy = 1;}
if($ENV{'HTTP_USER_AGENT'} =~ /via|cache|proxy|delegate/i){$use_proxy = 1;}
「=~ /A|B|・・・/i」は「AかBか・・・の少なくとも一つが含まれている」。USER AGENTに特定キーワードが含まれているか。
if($ENV{'REMOTE_HOST'} =~ /proxy|cache|via|delegate|www|mail/i){$use_proxy = 1;}
$ENV{'〜'}は環境変数です。「様々な環境変数を使って判断している」ということに注目して下さい。逆に言えば「『ここを調べればプロキシかどうか分かる』という場所はない」ということです。
もちろんリストに登録したプロキシの一部は上記のような「串弾き」にひっかかるでしょう。弾かれないプロキシもあるでしょう。
ReadMe!不正投票マニュアル(1)の方法では投票間隔が大体一定になります。例えば「前々回の投票と前回の投票の間隔」と「前回の投票と今回の投票の間隔」。
「大体一定」という言い方をしたのは、「回線の関係で正確に一定になる訳ではない」ということですが。
「正確に一定」でない以上、不正投票防止ルーチンがこの不自然さに気付くことはおそらくないとは思います。しかし人間は気付くかもしれません。つまりReadMe!スタッフがログを見れば。
不安ならばJavaScriptとの連動で「リロード間隔に乱数を使う」という処理を行えばいいでしょう。具体的なソースは書きませんが。
よく「プロキシ非万能性」を語る際に言われることですが、プロキシサーバーに接続ログが残ります。ReadMe!スタッフが「このサイトは不正投票をしていないか?」と目を付けた場合。プロキシサーバーにログ提出を求め接続者の生IPを知ることが可能でしょう。