LoveLangの熱き戦い
2週ほど前に私はLoveLangという小さなサイトをHeroku上に公開しました。ちょうどWebSocketを学んだばかりだったので、ちょっとデモを作ってその動作を試してみたかったのです。いつものようにそのことを、このブログとTwitterで告知しました。
何人かの人が来て、自分の好きな言語のボタンを数回クリックして、去って行きました。中にはそこに留まる人もいました。LoveLangはリアルタイムで見ている人の人数がわかるのです。
暫くは大した動きはなかったので、あらためてTwitterで投票を呼びかけてみました。これにfollower1800の@jugyoさんが答えてくれました1。するとTwitter上にLoveLangのリンクを貼ったTweetが増殖していきました。10前後だったUserCounterの値が30、40と増えていきました。円グラフ上の数値はすごい勢いでインクリメントしていきました。これを機に様相は一変したのです。
遂にはその声はfollower15000のRubyのパパにも届きました2。UserCounterは100を超えました。TwitterでもLoveLangを話題にしたつぶやきが多数見られました。LoveLangはプログラマの何かに火をつけたのです。
だんだんサイトが重くなって、新たなコネクションを張れなくなりました。そしてfollower45000の@dankogai氏が訪れたとき3には、コネクションは300を超えてさらに接続は困難なものになりました。
私は興奮しました。
円グラフの数値はすごい勢いで増えていき、各言語の値があっという間に10万クリックを超えました。Twitter上で特定の言語に対するクリック支援を要請する動きすらありました。そのような口コミの広がりが新たな参加者を呼び込み、グラフ上の数値は加速度的に増加していったのです。
サイト情報:lovelang.heroku.com - Ceron.jp
Twitter Trackbacks for Love Languages?
しかし、その中には明らかに人間の手に拠らない、すなわちスクリプトによる値の増加が見受けられました。Twitter上でもこれに言及する発言が増えていきました。LoveLangを「公認DoSサイト」とか、「自動クリックゲー」と呼ぶ人も現れました。考えてみれば怠慢・短気・傲慢を美徳とするプログラマに、「マウスをクリックして言語愛を示せ」とは無理な相談だったのかも知れません。
ここに至って私はやっと、自分が一部のプログラマに挑戦状を叩きつけていたことを知るのです…
深夜になってもClicked by Scriptは止まりませんでした。サイトはWebSocket実現のためにPusher4の無料プランを利用しています。しかしどういうわけかその制約を超えてコネクションは維持され、無数のClicked by Scriptをさばいたのです。
やむなく公開から8時間後一旦サイトを閉鎖しデータをリセットしました。腱鞘炎を顧みずコーディングも放り投げて、ひたすらクリックで言語愛を表明してくれた人たちには申し訳ない気持ちで一杯でした..
その日のメッセージ総数は信じられないことに1億に達していました。軽い気持ちで公開したデモサイトが、自分に未曾有の経験をもたらしました。私にはまともなサイトを公開した経験も、サイトセキュリティに関する知識も、頼れるプログラマの知人もいなかったので、ほんとうに戸惑いました。
深夜の連打祭り ~ lovelang.heroku.com ~ - Togetter
しかし有難いことに、Twitter上で対策の糸口となるつぶやきを見つけました。
みなさんもChromeのコンソールで for(i=0;i<10000;i++){document.getElementById(‘5’).click();} しましょう
そう犯人は現場に戻る習性があるのです!
早々私は対策に乗り出し、$(“button”).click を$(“button”).mouseup に変更して、再公開に踏み切ったのです。公開するやいなやコネクションは数十に達しました。暫くは対策の効果が効いて、Clicked by Scriptは静かになりました。
ところが1時間もしないうちに連続する高速のカウントアップが始まり、あっという間に値は10万に達しました。私は数時間でまたサイトの閉鎖を余儀なくされました。
私はまたヒントを探して、Twitter上のつぶやきを見守りました。そして「Ajaxのpostコールがidだけで行われている」旨の発言を見つけました。サイトでは言語ボタンをクリックすると、そのボタンのidと共に Ajaxのpostリクエストが発動してサーバ側に渡ります。サーバはそのidから対応言語のカウンタをインクリメントしてPusherに渡します。PusherはそれをWebSocketを介して各Browserにブロードキャストするのです。
Clicked by Scriptが行われているときにpostリクエストのend pointを変更してみると、果たしてカウンタはストップしました。マウスクリックをシミュレートするスクリプトではこうなりませんから、これで犯行の手口がはっきりしました。
私は早々対策に乗り出しました。WebSocketではBrowserのタブ毎に固有のソケットIDを割り当てるので、postリクエストにこのIDを共に渡すようにしました。またend point側でunless request.xhr?の記述を追加して、postリクエストをAjax限定にしました。
サイトを再開すると、すぐに数十のコネクションが張られましたが、Clicked by Scriptは止みました。私はこれでLoveLangに平和が訪れることを期待しました。
しかしその期待はすぐに裏切られることになりました。暫くするとpostリクエストに、ソケットIDを渡すscriptが書かれ、私の防潮堤は簡単に破られました。またしても私の認識は全然甘かったことを思い知るのでした。
私はサイトを閉鎖し再度対策を検討しました。そしてpostリクエストにsessionデータを含む、いくつかの固有データを共に渡すようにしました。sessionデータはAES 256で暗号化し、改ざんされた場合はリクエストを拒否するようにしました。
またリクエストのend point名を「clickbyyourfingertipplease.json」に変え、サイトには「run is not love, but click is.」と表示し、更にはTwitterで「少し愛して、長く愛して」とつぶやいて、その良心に訴えるように努めました.. ^ ^;
そしてそのどれかは一定の効果を奏しました :) postリクエストを偽装した侵入は激減しました5。
しかしその一方で別の言語に対する別の手口による犯行が始まりました。今度はpostリクエストのend pointを変えてもカウンタはストップしません。
マウスクリックのシミュレートに対してはclickイベントをmouseupイベントに変えただけの対策しかできていませんでした。そこでカーソルがあるべき場所にあるときだけ、mouseupイベントが発動されるようにしました。
この対策も一定の効果はありましたが、それが効かないスクリプトもありました。java.awt.Robotのような、カーソル自体を制御するライブラリを使えば人間のマウス操作をシミュレートできるからです。
ここに来て私は、自分の実力とサイトセキュリティの限界を見ました。
「どんなに高い壁を作ってもそこを乗り越えてくるやつはいる」。3.11の教訓が私には全く生かされていませんでした..
そこで視点を変えてみることにしました。Clicked by Scriptを受け入れることにしたのです。一方で、一定時間内のクリック数を制約するルールを入れたのです。この制約はもちろん、真面目にクリック(?)している人にも働きますが、人間はこれに対応できますし、彼の腱鞘炎を防止するためにも適切な措置なのです。
2週間が過ぎてLoveLangにはかつての熱狂はなくなりました。それでもLoveLangをちょっと覗いて自分の愛する言語にクリックしていく人がいます。この1週間は平穏な運営が続いています6。
今となっては私が施した幾つかの対策が功を奏しているのか、それとも、「自動クリックゲー」に彼らが飽きたのかはわかりません7。「lovelangとは何だったのか」などと、あの熱狂を振り返って哲学的なTweetをする人もいました。
昨日こんなうれしいTweetを見ました。
今宵はマッカーシー教授を偲んで#lovelangでもするか.8
LoveLangは今も生きています。
昨日、 言語関連Tweetを表示するリニューアルを施しました。これからもLoveLangをどうぞよろしくお願いしますm(__)m
- https://twitter.com/#!/jugyo/status/123773761534177280 ↩
- https://twitter.com/#!/yukihiro_matz/status/123790343064924160 ↩
- https://twitter.com/#!/dankogai/status/123794000854515712, https://plus.google.com/103748274114027132441/posts/1wj37XUnHB6 ↩
- http://pusher.com/ ↩
- 完全になくなったかは定かではありません ↩
- この投稿が新たな火種にならぬことを祈ります ↩
- まあ後者の理由でしょうね ↩
- https://twitter.com/#!/mkamotsu/status/128777158691786753 ↩
blog comments powered by Disqus