認証用URLを短縮しちゃいかん
認証用URLなんぞをURL短縮サービスで短縮する奴なんかいないだろうと思う方も多いと思いますが、URL短縮について調べていたら、これをやらかしかねない人をちらほら見かけたもので。認証用URLを短縮することの問題点というのを簡単に言うと、攻撃者があてずっぽうで短縮URLにアクセスして認証できてしまう危険性が高いということです。
この問題点の怖いところは、
- 長い認証用URLを提供したい「提供者」に悪意がなく、
- 長いURLと短縮URLを相互に変換する「短縮者」に問題がなく、
- 認証用URLを利用する「利用者」が気をつけていたとしても、
提供者の意識の甘さ一つで利用者のアカウントが攻撃者に乗っ取られる可能性があるということなのです。
提供者というのは例えば何かの会員制サイトであり、短縮者というのは例えばTinyURLやp.tlなどのURL短縮サービスであり、利用者というのは会員制サイトに登録したい人です。
認証用URLというと、利用者が本当に本人による操作なのかを確かめるための長いID(典型的には十数桁以上)が後ろにくっつきます。このIDが長いからこそ攻撃者にはそのIDがわからず、利用者は成りすましの被害を受けることがないのです。これをごっそり取っ払って短縮URLにすると、攻撃者はわずか数文字の予測可能なURLを使うだけで他人の操作を奪取することができるわけです。
例
では、オンラインショッピングサイトを想定して具体例を見てみましょう。
登場人物は以下のようにします。
- 提供者:exampleオンラインショップ(www.example.com)
- 短縮者:example短縮サービス(s.example.com)
- 利用者:松田さん
- 攻撃者
ここで、example短縮サービスは、exampleオンラインショップが自社提供しているURL短縮サービスで、exampleオンラインショップだけが使っていることとします。この問題では、短縮URLのパターン数がより少ない自社提供の短縮サービスのほうが大手より危険であるため、このように設定しています。
以下、主語、つまり行動の主体を太字で表記しています。
まず、利用者の松田さんが、exampleオンラインショップに会員登録しようと、会員データとして住所氏名電話番号およびメールアドレスとパスワードをexampleオンラインショップを送信します。もちろん会員データはSSLで暗号化して送られるのでちょっとやそっとじゃ盗聴なんてされないでしょう。
exampleオンラインショップは、松田さんが正しいメールアドレスを登録したかどうか確かめるため、松田さんのメールアドレスに向けて送る認証用URLを生成します。ここでは、出来合いのショッピングサイト構築ソフトが作ったURLにしておきましょう。
ショッピングサイト構築ソフトはきっとだれにも予測できないような認証ID「f6472dd1838795f2be744d3fa602aae3」を生成し、「http://www.example.com/auth.php?authid=f6472dd1838795f2be744d3fa602aae3」なんて長ったらしいURL*1を作り出すことでしょう。この「http://www.example.com/auth.php?authid=f6472dd1838795f2be744d3fa602aae3」にアクセスすれば松田さんは晴れて本会員になり、ログインして松田さんの個人情報を使ってお買い物ができるわけです。
で、exampleオンラインショップは「こんな長いURLなんか送ったら松田さんは大変だろう」などと余計な気を利かせてexample短縮サービスを使ってURLを短縮するわけです。
ここで、example短縮サービスは、短縮URLを「http://s.example.com/(連番)」という形式で作ることにします。たとえば、「http://s.example.com/999」の次は「http://s.example.com/1000」になります。短縮URLやってみようかなって思った人がまず試しそうな素朴な実装*2ですね。
今回、exampleオンラインショップがexample短縮サービスを使うのは6473回目だったとすると、認証用短縮URLは「http://s.example.com/6473」になります。
一方、攻撃者は常日頃からs.example.comをチェックしていて、「http://s.example.com/6472」は既に使われていて「http://s.example.com/6473」はまだ使われていないことを知っていました。つまり、次にURLが短縮されるとしたら必ず「http://s.example.com/6473」になると知っているのです。なので、次に認証用URLが短縮されたら、すでに知っている「http://s.example.com/6473」にアクセスするだけで誰かのアカウントを乗っ取ることができるわけです。
認証用URLが短縮されたらあとは時間との勝負です。
exampleオンラインショップがexample短縮サービスから短縮URLを受け取り、松田さんにメールで短縮URLを送信し、松田さんがメールを受信し、ブラウザを立ち上げ、短縮URLに攻撃者より先にアクセスすると、exampleオンラインショップと松田さんの勝利です。松田さんは本会員となり、認証用URLは無効化*3され、攻撃者は松田さんとして会員になることができず、あきらめて「http://s.example.com/6474」を狙うほかなくなります。
ではもし攻撃者が先に短縮URLにアクセスしたらどうなるでしょう。これは、「http://s.example.com/6473」をブラウザのアドレスバーに入れたまま移動ボタンを何秒かに一回程度押すだけで割と簡単に成功します。もしアクセスしたときまだ認証用URLが有効であれば、攻撃者は松田さんとして本会員になり、松田さんとして松田さんの会員データを使ってお買い物ができるわけです。ついでにパスワードを抜き取れば他のオンラインショップでも使えるかもしれませんね。
このようにして、攻撃者は通信の盗聴すら必要とせず、簡単なURLにアクセスし続けるだけで誰かのアカウントを乗っ取れてしまうということです。そして、利用者の松田さんができる唯一の抵抗は、なるべく早く短縮URLにアクセスすることだけなのです。
ちなみに、松田さん自身が攻撃者と同じ行動をとった場合、認証用URLを記載したメールアドレスを受け取る必要がないので、嘘のメールアドレスで会員登録できてしまいます。これはこれで問題ですね。
効果的ではない対策
この問題は認証IDの情報量がURLからごっそり抜け落ちてしまう点にあるので、情報量を減らしたままではどんな対策も根本的な解決には繋がりません。
大手のURL短縮サービスを使う
自社提供したほうが危険と書きましたが、それは同じ数の攻撃者に同じように狙われていたら、の話です。大手ならば攻撃者の数も当然多いでしょう。
生成される短縮URLを連番以外にする
確かに連番よりは遥かにましになります。しかし、やはり認証IDから減った桁数の分だけ、文字通り桁外れに危険なのです。
認証URLにアクセスしたときパスワードを尋ねる
攻撃者はパスワードを知らないはずなのでアカウントを乗っ取ることはできないでしょう。確かにある意味効果的です。しかしURLを短縮して利便性を図った結果、認証に必要なステップが増えてしまっては、かえって利便性が損なわれるように思います。
また、利用者による嘘のメールアドレス登録も防げないことになります。
認証URLにアクセスしたときIPをチェックする
つまり、登録したときと同じIPならば本人だと判定するという方法です。上記の方法と比べて利便性の問題は解消されていますが、メールアドレスを偽れる問題は残っています。
認証URLを使用する理由を考えると、この方法も効果的ではないことでしょう。
どのように短縮すれば問題ないか
問題点を裏返すと、認証IDの情報量を減らさない限り、いくら短くしても構わないのです。
認証ID以外の部分を短くする
例えば「a.b」というドメインを取得して、「http://a.b/f6472dd1838795f2be744d3fa602aae3」へのアクセスを「http://www.example.com/auth.php?authid=f6472dd1838795f2be744d3fa602aae3」に飛ばすようにすれば、認証IDの安全性を残したままそれなりに短縮できます。
認証IDの冗長性を省く
簡単に言うと、短くても同じだけの情報量を持つように「圧縮」するということです。
例えば、例に使った認証ID「f6472dd1838795f2be744d3fa602aae3」は16進数表記なので、0〜9、a〜fの16種類の文字しか使っていません。g〜zとかA〜Zとか「-」とか「_」とかも使えるのに使っていないから、長くなるのです。
これを、g〜z、A〜Z、「-」、「_」も使って64進数表記*4にすれば、「3ShOThwUulYHVQjj-C0GHz」となります。あまり短くなっていないように思われますが、これでも3割強短縮されています。
終わりに
URL短縮には様々な問題点や危険性が指摘されています(参考:http://goo.gl/fWylz *5 )。しかしそのほとんどは以下の2つのパターンのどちらかでした。
- 提供者に悪意があり利用者が被害を受ける(URL隠蔽)
- 短縮者に問題があり提供者と利用者の利便性が損なわれる(サービス停止)
これらは、確かにURL短縮にもある問題ですが、根本的には「リダイレクト」一般の問題です。
今回、「URLを短縮すること」そのものによって発生しうる問題について述べました。
実際のところ、認証用URLが短縮されたためにアカウントが乗っ取られたなんて話は聞いたことがありません*6。
ただ、これから長いURLを誰かに提供しようとする人は、そのURLを短縮する前に、本当にそのURLは短くても良いのかを考えてみる必要があるでしょう。
*1:今回、authidの値にはPHPのセッションIDを用いました。
*2:素朴な実装ではありますが、短縮すべきURLが多くないと分かっている場合にはこれで充分なのです。今回のような問題が起こらなければ、の話ですが。
*3:さすがにまともなショッピングサイト構築ソフトならこれをやらないなんてことはありえないでしょう。提供者の問題を取り上げているので他はまともであることが大前提です。
*4:BASE64では2種類の記号は「+」と「/」なのですが、URL上で特別な意味を持つ記号なので今回は別の文字を使いました。