Hatena::Groupbugrammer

蟲!虫!蟲!

28歳の無職です。仕事を探してます。-> Esehara Profile Site (by Heroku)
 | 

2011-09-06

ザ・インタビューズが凄かったのは、セキュリティーなんて全く感じられない作りなのに、ユーザーに支持されたという点にある。 05:48

長文注意。文責は "@esehara" です。

前置き

 元々、ザ・インタビューズは流行らないとしか思っていなかった。

 少なくとも友人に関しても「Twitterみたいなサービスがあるのに、長文を書かせるサービスなんて……」と言っていたし、他の人も同様。一過性の流行りだろうな、という議論はあるわけで、それは半年後になってみないとわかんない。それでも、登録数が現時点で、確認したところによると累計六万ユーザーを超えている。PVも200万を突破している。もうちょっとした中規模サービスの流れに乗っている。

 インタビューズに関しては語りたいことは多くある。既に「インタビューズが流行ったのはなぜなのか」「インタビューズが面白いのはなぜなのか」みたいな話もたくさん出ている。でも、わざわざ自分のスクリプト勉強ブログにてこういうことを語るのは、そういう点じゃない。インタビューズが凄いのは、素人目に見てもWebサービスならことごとくやっちゃいけない実装を踏襲していているんじゃないの?という点にある。

ザ・インタビューズが開発された経緯を見てみよう。

 そもそも、ザ・インタビューズが開発されたきっかけというのは、Paperboy&Co.という会社が行っている「お産合宿6 5」というイベントのことでだ。これはチームを作り、一泊二日で何らかのサービスを作り上げるというイベントだと説明されている。で、その中でザ・インタビューズは作られたらしい。自分のことを考えると、一泊二日でサービスで作れる構築力は凄いとは思う。そこは素直に凄いと思う。

 で、普通の開発期間が一泊二日のサービスなんだから、バグが出続けるのも当然だし、そういうのは運営の最中にソースを見直して、ちょこちょこと脆弱性を塞ぎつづけるものだと思っていた。そういうのがWebサービスの運営方法だと思うし。でも、どうやらそうではなかったらしい。

恐らくやっちゃいけない実装:他人のリスト追加を操作できる

 ここからは、外部の挙動から推測できる話になるので、興味ある人達が読んでくれれば幸い。技術話(というほどでもない低レベルのお話)が読みたくなければ、最後の章だけ読んでしまえば幸い。

 ザ・インタビューズは、リスト追加するさいに、JavascriptのSubmitを使用して行っている。確かユーザー登録数5000人の頃だったと思うんだけど、HTMLでソースを読んでいた。それは手動でリスト追加するのも面倒くさいし、簡単にリスト追加できるスクリプトでも書きたいな、と思っていた。すると、次のような実装になっていた。

<a href="#" onclick="follow.user_id='2009';follow.target_user_id.value='6551'; remove.submit(); return false;" class="add"></a>

 その当時は新着ユーザーからリストを見ていたのだが、follow.target_user_idは連番で変わっていくため、これが恐らくデータベース上で管理されている内部ID名なのではないか、ということは理解出来た。しかし、問題はuser_idという部分。経緯はすっとばすけれども、この内部ID名こそ、自分のIDだったのだ。

 でも、この部分は本来不必要な部分だ。というのも、セッション管理をしているならば、セッション情報なりを習得し、ログインしているユーザーの操作として投げ返してあげればいい。実際に、質問の段階や、プロフィール変更の場合では、上記みたいな変な実装にはなっていなかった。不要な部分というのは大抵バグの温存になりがちなのだが、この例も一緒で、user_idを任意の番号に変更してあげると、その内部IDに振り当てられたユーザーが恰も操作できてしまうという脆弱性の元になっていた。なものだから、例えばスクリプトの実装例として、follow.user_idを連番にしてやり、逆にfollow.target_user_idを自分のIDにすることで、簡単に全員のユーザーに対して無理矢理リスト追加操作ができるということができてしまっていた。

 この脆弱性は、あまりにもありえなかったし、小規模サービスだし、いつかは治ると思っていた。でも全く治らなかった。そして、次なる脆弱性が見つかってしまった。

 ちなみに、今現在では対策を取られているものの、この脆弱性の名残りは、このエントリを書いているときにも確認することができる。ユーザーのページなり、あるいは新規メンバーなりのHTMLソースを見てみよう。

<form name="follow" action="/follow" method="post">
<input type="hidden" name="mode" value="follow" />
<input type="hidden" name="user_id" value="" />
<input type="hidden" name="target_user_id" value="" />
<input type="hidden" name="page" value="/esehara/" />
</form>

ね?あるでしょ?

おまけのバグ:target_user_idは何でも指定できた

 Javascriptを開発している技術者だったら、Firebugなりの"Javascriptコンソール"を叩くという経験は多くあると思う。例えばChromeだったらデフォルトでついている。てなもんだから、ページに対して、ある程度意図的な操作が可能になる。

 そのとき、Hamachiya2のインタビューを読んでいた*1。すると下のようなことがかかれてあった。

学習法は知らないけど、セキュリティに限らずバグのないコードを書く為には

想像力が大事だと思う。

たとえば「ここは数字が入力されているはずだから」ってことで

入力された値をそのまま計算しちゃうコードだと、

「もし数字以外が入力されていたら?」

「もし割り算なのにゼロが入力されていたら?」

みたいな、いわゆる「異常系」が沢山あるよね。

それをどれだけ想像できるか。

 ……とすると、target_user_idにはどんな番号でも指定できるのではないか。実際に負数を入力してみたり、単なる文字列を入れてみたところ、それは通ってしまった。リストにちゃんと追加されている。これはたぶん特に何の問題も起こさないバグなんだけど、友人が気づいていればかなりゆかいとんでもないことになっていたと思う。

恐らくやっちゃいけない実装:アカウントを脱退したユーザーの操作を塞がない

 さらに、もう一つの変な実装を見つけてしまった。

 友人が余りにも調子乗りすぎて、卑猥な単語ばっかりを貼り付けまくってしまい、アカウントをバンされてしまったことがあった。でも、アカウントをバンされたとしても、"http://theinterviews.jp/hogehoge/profile"は依然として残り続けていた。このバグに関しては他の人からも指摘されており、脱会処理を行ったとしてもメールアドレスに、リスト追加報告などが送りつけられるというバグが動き続けていた。

 これは何を意味するか。アカウントは脱会処理をしていたとしても、依然として内部の機能としては生き続けてしまう、ということだ。

 アカウントを削除しない理由は理解できる。何らかのきっかけでアカウントを復活させたい場合、アカウント情報がなければどうしようもない。あるいは今後の障害が起きたさいに検証する作業にもなるわけだし。問題はここにあるのではなく、アカウントが生き続けてしまったという点にある。

 どういうことかといえば、普通、期待される実装としては、アカウントの脱会処理というか、データベース的に脱会のフラグが立てられたユーザーは、リスト追加、リムーブ、質問を送りつける、などの機能がブロックされる必要があると思うのだが、それをやっていなかった。要するに、アカウントをバンされたとしても、内部の操作がブロックされないため、何らかの脆弱性によって、そのアカウントが操作可能となったとき、そのユーザーからリスト追加されてしまうという脆弱性が生まれるということだ。

 具体的に言うなら、アカウントバンなり、脱会なりで行っていたのは、ユーザーページの非表示と、ログインブロックのみだったのではないか、と思う。たぶん、こういう実装になってしまったのは、最初の段階で脱退機能が無かったため(初期の頃に「辞めたいけど辞められない」という苦情が相次いだ)、突貫で作った動作がこれだったような気がする。

 実際に、テスト用アカウントを作成し、二つの違う種類のブラウザを立ち上げ、片方で脱会処理してみよう。そして、脱会処理を行わなかったブラウザで、ザ・インタビューズを見てみると、普通にリスト追加であったり、質問が出来たりする。殆ど脱会の意味がない。

謎の未読1バグの発生へ

 ……という話を友人にしてみたところ、「あ、面白いことを思いついたから、ちょっと試してみるわ」といった。何をやらかすんだ、と思って見ていたところ、「そのバンされたアカウントから一斉にユーザーを送りつけてみた」と。友人曰く、「サーバーの負荷攻撃になるかもしれないけど、なんか閲覧できないユーザーからリスト追加の報告が来たら気持ち悪くていいよね」ということを言っていた。かなり悪趣味だし、訴えられたらどうするんだとは思っていたが、そのときはまだ笑い話だった。

 ちなみに、そのとき書かれたスクリプトが下のようになる。

require "rubygems"
require "mechanize"
max_id = 50000
min_id = 1
account = "robot666"
password = "xxxx"
user_id = 1909

browser = Mechanize.new
print "Login... \n"
browser.post("http://theinterviews.jp/login",{["account",account],["password",password]})
print "Success!! \n"
while true
    print "Add List Start.\n"
    for i in min_id..max_id
        begin
            print "Now Target_User_Id is " + i.to_s + "\n"
            browser.post("http://theinterviews.jp/follow",{"user_id" => user_id.to_s,"target_user_id" => i.to_s,"mode" => "follow","page" => "http://www.google.com/"}) rescue Exception
        end
    end
end

 で、これを廻しまくっていたらしいのだが、別の友人が変なことに気がついた。「あのさ、インタビューズのことをウォッチしていたんだけど、なんか消えない未読1の不具合が発生しまくっているらしいよ」ということだった。これは予想外の出来事だった。要するに、データベースの内部で、そのユーザーは存在しないのにも関わらず、リスト追加を送りまくっているものだから、データベースにズレが生じ、未読状態になっているのにも関わらず、肝心のメッセージが表示されないというバグが起きてしまったということだ。

 現在では、対策が取られているため、上記の遊びは出来ないけれども。

ザ・インタビューズの教訓みたいなもの

 ザ・インタビューズの教訓みたいなものがあるとするならば、結果として次の点にあると思う。ちょっと煽り口調になってしまうので、不愉快な人もいるとは思うけれども。

 まず一つに、Webサービスはまずアイデアだして立ち上げてみればいいのであって、セキュリティの問題とかは徐々に勉強していけばいい。自分なんかは人のIDを預かるなんていうのは、「もしバグが起きてパスワードとか流失させてしまったらどうしよう……」ということで不安になるんだけど、その不安というのはちょっと杞憂であると思う。上記の脆弱性だって、HTMLのソースを読んでしまえば、ちょっとした高校生ですら突けてしまうかわいいものだ(効果は絶大だけど)。まずは立ち上げる。で、失敗したら諦める。

 多くの場合、Webサービスというのは、表まわりであったり、あるいはデザインであったり、「形になっていること」のほうが説得力もあるし、重要なんだろう。まずは動くということ。そもそも形がないと「こういうサービス作ったんですよ」ってプレゼンが出来ない。頑張って内部のロジックを完璧に作り上げたとしても、そういうのに興味ある経営者とユーザーというのは、あんまりいない。いるとすると、同業のエンジニアくらいなのかな、と思ったりする。

 自分自身は、そういう裏側のエンジンやロジックを作っている人には敬意を払いたいけれども、なかなかそういうのに敬意を払うのは難しいんじゃないだろうか。俺は製本の工場で一時期アルバイトをしていたけれど、糊付けの技術なんていうのは、なかなか目がいきにくい。それよりも、デザインがカッコイイとか、そっちのほうが華がある。どっちも大切だけど、でもWebサービスなんていうのは、恐らくそういうものなんだろうと思わされた。

 まだ、たぶん変な脆弱性はあると思うので、「こういう実装はしてはいけないんだな」という勉強がてらにいじり倒してみようとは思っている。俺はHamachiya2みたいにカリスマ性も、セキュリティー関連に詳しくないので、一から覚えるのにはいい素材になっている。そういう意味では、ザ・インタビューズに感謝している。

 あと、ついでだから書いておくと、ユーザー側で気をつけておきたいことは、ベータ版のWebサービスは、かなりひどい実装をしている可能性もあるということを覚悟して使うこと。少なくとも、セキュリティー的にある程度いじられまくってからか、セキュリティのチェックを基本としている人が何らかの形でコードレビューしているという信頼が必要なんだろうな、と思う。これは別に非難していたり、皮肉ったりしているわけじゃなく、ベータ版のサービスというのはそういうものだと、俺は思っている。そして、そのサービスがどのレベルのコーダーなのか、というのは外部からは見えない。少なくとも俺みたいなエンジニアの卵未満ですら、「これおかしいだろう」という実装がされていたのだから、そういうものだと思う。

しゅうしゅう2011/09/08 11:08いまHP見たら、お産合宿5となってましたよ。

nisemono_sannisemono_san2011/09/16 04:14修正しておきました。Thanks!

 |