意図的な攻撃でなく偶発的な事故なのかもしれないが、auの公式サービス「au books」のEZwebサイトで、Webアプリケーションの脆弱性が原因の情報漏洩事故が起きたようだ。
ゲーム攻略本(1冊1890円)の紹介サイトからアクセスし、その攻略本を買おうとすると、他の顧客の氏名、住所、電話番号、生年月日、会員パスワードが表示された。そのまま購入手続きをとると、他の顧客が購入したことになってしまうという。
1. 発生事象
本年6月22日20時37分から23日18時45分までの間、特定のリンク元サイトから「au Books」にアクセスしたお客様に対し、同じ時間帯にアクセスした他のお客様の登録情報 (氏名、住所、電話番号、生年月日、会員パスワード) が表示され、場合によっては、自分の情報が他のお客様の情報に書き換わってしまう事象が発生しました。 なお、誤って表示された可能性のあるお客様情報は最大436件、また書き換えられた可能性のあるお客様情報は最大124件です。
2. 発生原因
リンク元サイトから、「au Books」にアクセスしてきた同一のセッションIDを持つお客様に対し、「au Books」が、個別のセッションIDを付与できなかったために発生しました。
KDDIの発表に技術的な原因が書かれていて有益だ。この記述から推測するに、session fixationが起きていたのではないか。
対策が完了してサービス再開された後のau booksを訪れてみると、次の構成になっているようだ。
その他、secure属性の付けられたcookieと、他に数個のcookieが発行されるようになっている。
改修前とどの部分が違っているか(対策により)は確認できないが、以下、事故当時に何が起きたのかを推測してみる。
まず、「特定のリンク元サイトからau Booksにアクセスしたお客様」に限ってこの現象が起きたということから、おそらくそのリンクは、次のように、セッションID入りのURLで記述されていたのだろう。
http://www.au-books.jp/item_detail.html;jsessionid=E34C50...?item_cd=MJ070.....
このリンクを辿ってアクセスするとき、現在の改修後のシステムでは、このセッションIDは破棄されるようだ。もし「JSESSIONID」というcookieに既に値が入っていれば、そちらの値が優先され、アクセスしたページに(URL rewritingで)埋め込まれる次のリンク先のURLには、そちらのセッションIDが埋め込まれる。また、「JSESSIONID」のcookieがまだ存在しない場合には、新たにセッションIDが発行されて、その値がSet-Cookieされ、次ページへのリンクのURL rewritingに用いられる。つまり、URL中の「;jsessionid=E34C50...」の部分は実質的に使用されていないに等しい構成になっているようだ。
これが、改修前では次のように動作していたのではないかと推測する。「JSESSIONID」のcookieがまだ存在しない場合、URLに指定された「;jsessionid=E34C50...」がセッションIDとして認識され、その値が「JSESSIONID」のcookieとしてセットされる――(A)。(あるいは、「JSESSIONID」のcookieが発行されていなかった可能性――(B)もある。)
こうした動作をすると、同じ時間帯にアクセスした複数の閲覧者が、同じ「E34C50...」のセッションIDでアクセスすることになる。ここで、Webアプリの構成が次のようになっていたとしよう。
その場合、一人目のユーザ(1)がログインした後に、別のユーザ(2)がログインし、その後にユーザ(1)が個人情報を表示しようとすると、セッションオブジェクト内のユーザIDは(2)のユーザIDに書き換わっているため、ユーザ(1)の画面にユーザ(2)の個人情報が表示されるという事態が起きる(図1)。
通常「session fixation」という用語は、この脆弱性を持つWebアプリに対する意図的な攻撃を指して用いられる*2が、不慮の事故によって起きるこうした事態についても、「session fixation」という言葉を使ってよいのではないだろうか。
特に、上記(A)のケースは、session fixationの中でも、その一形態である「session adoption」が起きていたと言える。「session adoption」とは、session fixation脆弱性に名前を付けた最初の論文「Session Fixation Vulnerability in Web-based Applications」で、攻撃手法の解説として、指定のセッションIDをブラウザに送り込む方法を列挙している中で定義された言葉であり、次のものを指す。
まず、WebアプリケーションがセッションIDをブラウザのどこに格納させる構成になっているかで分類すると、(a) URL引数への格納、(b) hiddenなINPUTフィールドへの格納、(c) cookieへの格納の3つ形態あるわけだが、(c) の場合に、攻撃者サイトから他のドメイン用のcookieをどうやってセットするのかが問題となる。攻撃対象サイトにクロスサイトスクリプティング脆弱性がある場合にそれを悪用するといった方法の解説がある中、他のケースとして挙げられているのが、「session adoption」である。
Session adoption
Some servers (e.g., JRun) accept any session ID in a URL and issue it back as a cookie to the browser. For example, requesting:
http://online.worldbank.dom/?jsessionid=1234
sets the session cookie JSESSIONID to 1234 and creates a new session with that ID on the server6. We'll call such behavior "session adoption", due to the fact that the server effectively "adopts" a session ID that was generated by someone else.6In JRun, it is required that a session with the proposed ID doesn't exist on the server yet in order for the server to return the session ID cookie. This may be different in other systems with similar behavior.
(訳)
セッション養子縁組
いくつかのサーバ(たとえばJRun)は、URLに書かれた任意のセッションIDを受け入れ、それをcookieとしてブラウザに発行し返す。たとえば、
http://online.worldbank.dom/?jsessionid=1234
というリクエストを出すことは、セッションcookie「JSESSIONID」を「1234」にセットし、そのサーバにそのIDで新たなセッションを作成する6。サーバが実際上、他の何者かによって生成されたセッションIDを「adopt」する(養子にする)という事実から、我々はこのような挙動を「session adoption」(セッション養子縁組?)と呼ぶ。6JRunにおいては、サーバがそのようなセッションID cookieを返すためには、提出されたIDによるセッションがそのサーバにまだ存在していないことが必要とされる。これは、同様の挙動をする他のシステムとは異なるようだ。
Session Fixation Vulnerability in Web-based Applications, 2002年12月
この脆弱性を持つWebアプリサーバとしてはPHPが最も有名であり、PHPセキュリティ界隈では「session.use_only_cookies をオンに設定する」ことが鉄則として叫ばれている。しかし、PHPだけでなく、上の文献にも書かれているように、J2EEのWebアプリサーバにも同様の挙動をするものがあるらしい*3。
au booksのサイトでどのWebアプリサーバが使われていたのかは知らないが、他のサイトでも注意が必要だろう。
一般に、session fixationの対策は、次のいずれかを達成すればよい。
セッションをfixされないようにするには、まず1つにsession adoptionが起きないようにすることである。セッションIDの格納場所として前記の(a)や(b)を採用せず、(c)を採用した上で、session adoptionが起きないWebアプリサーバを使う*4。しかし、残念ながらそれだけでは解決しないのが現状である。2006年10月21日の日記に書いたように、ブラウザに「Cookie Monsterバグ」があるとそれができてしまうのであり、ほとんどのブラウザで未解決だからだ。ただし、サイトを構築したドメイン名によっては影響を受けない場合もある。au booksの場合は、「au-books.jp」であるから、第2レベルで確定するので「Cookie Monster」の影響を受けないであろう。また、携帯電話のブラウザの「Cookie Monsterバグ」がどうなっているかは興味深いところだが、まだ調べていない。
セッションをfixされても問題がないようにする場合、最も単純なのは、ログイン後までセッションIDを発行しない(セッションを作成しない)ようにすることであるが、au booksのように、ログイン前からショッピングカートのためにセッションを作成する必要がある場合には、それを採用できない。
そのような場合においては、ログイン直後にセッションIDを振り直すという方法が知られている。しかし、はたしてそれで解決なのだろうか。2006年10月29日の日記「ログイン前Session Fixationをどうするか」に書いていたように、ログイン前の状態をセッションハイジャックされた場合、何かの被害が出ると言えるかが焦点となる。
ショッピングサイトの場合、買い物をしようとしている被害者が、悪意あるサイトからのリンクを辿ってサイトに到着した場合、買うつもりのない商品までカートに入れられていることに気づかずに決済画面に進んでしまうということが起こり得るが、攻撃が成功する確率は低めであるし、はたしてそのような攻撃を誰がしたいと思うか? という疑問がある。
だが、今回の事故では、誰も意図していないのに、数百人もの人が同じセッションを共有してしまう事態が起きたわけだ。これは、リンク元が信頼のおけるサイトだったことがひとつの要因であろう。「攻撃」ではなくても、事故でセッションのfixationが起きれば、誤発注が多発してサービスを中止せざるを得ない事態が生じ得る。
その意味で、少なくとも、意図せずセッションをfixするようなリンクができてしまう事態はいかなる場合も避けた方がよいということは言えそうだ。幸い、session adoptionを避ける方法はあるのだから、Webアプリサーバをそのように設定すればよい。
残る問題は、「Cookie Monsterバグ」を突いてたとえば「.co.jp」全域で有効な「JSESSIONID」を発行するようなサイトが存在する場合であるが、意図的な攻撃でなく、誤設定でそのようなことをしているサイトである場合には、そのセッションIDは固定であるから、(最初を除いて)必ず無効なセッションIDとなっているはず*5なので、存在しないセッションの「JSESSIONID」cookieを無視する(受け入れてしまわない)ようにしておけばよい*6。
そうすると最後に残るのは、意図的に特定サイト用の新鮮なセッションIDをコピーしてCookie Monsterでセットしてくる攻撃(まさにsession fixationの典型)であるが、ログイン前でそれをされることがどのくらい困る事態なのかによって、対策しなくてよい場合もあるかもしれない。
このようなsession fixation対策が面倒だという場合、携帯電話特有の対策方法として、サブスクライバーIDを用いる方法が考えられる。
上記の図1でも、ログイン時にサブスクライバーIDを参照してセッションオブジェクトにuseridとして格納したわけだが、それをせずに、view操作の際に直接サブスクライバーIDを参照するようにすれば前述の問題は起きない。これは、サブスクライバーIDがアクセス毎に毎回送られてきているから実現できることだ。
別の方法として、ログイン時にセッションオブジェクトにサブスクライバーIDを記憶し、その後の各ページのアクセス時に、リクエストに含まれるサブスクライバーIDとそれが一致しているかを確認する方法もあり得る*7。それはちょうど、2007年2月23日の日記「携帯電話向けWebアプリの脆弱性事情はどうなっているのか」で参照した、WEB+DB PRESS誌Vol.37に掲載の記事「携帯サイト開発 実践テクニック 2007」にも書かれていたことである。
携帯サイトでセッションを使うときの注意点
携帯ブラウザの場合,Cookieを使うことができませんので,セッションを使う際はどうしてもURLにセッションIDが含まれてしまいます.URLにセッションIDが含まれる場合はセキュリティに注意する必要があります.
本人以外がセッション付きのURLにアクセスできないようにしましょう.特に検索サービスにクロールされてしまうと問題は深刻です.個人情報が簡単に検索できてしまいます.
そのため,セッションには必ず端末IDを保存しておいて,特定の端末のみアクセスできるようにしておきましょう.(略)セッションに格納されている端末IDと照合することで,違う端末からのアクセスをチェックすることができます.
携帯サイト開発 実践テクニック 2007, 技術評論社 WEB+DB PRESS Vol.37, p.127
改めて振り返ってみると、携帯用Webサイトではこれまでにもたびたび「誤表示」の事故が起きていた。例えば次などの報道があった。
こうした事故は、いわゆる「race condition脆弱性」(メモリ上のオブジェクトが短時間にセッション間で共有されるプログラムミスや、同じ名前の一時ファイルを使用してしまう欠陥などが原因で、高負荷時に発現するもの)によっても起きることが知られてきたが、今回のau booksと同様に、session fixationによって起きていたものもあったのかもしれない。
「携帯向けWebアプリは危ない」という話は以前からいろいろな人から耳にするが、具体的なことが表立って語られることがほとんどなく、安全な実装が普及しないという問題があった。
上のWEB+DB PRESS誌の記事の著者は、session fixationによる誤表示の問題が実際に起きていることを知っているがゆえに、「URLにセッションIDが含まれる場合はセキュリティに注意する必要があります」と書いたのかもしれない。
その対策方法として、サブスクライバーIDを用いることが書かれていたわけだが、私はその方法をお勧めしない。auの場合にはcookieがサポートされているのだから、cookieを使って、PC向けサイトと同様に対策をすればよい。(au booksはおそらくそのように対策されていると思われる。)
サブスクライバーIDを使わないべきなのは、次の理由による。
サブスクライバーIDは、ユーザに固定の固有IDであり、どのサイトにも同じ値が送信されるものであるため、国民総背番号制に対して示される懸念と同様のプライバシー上の問題がある。そのうえ、ワンクリック不当請求などに悪用される差し迫った現実の危険性も存在するため、できるだけ早く廃止すべき仕組みである。もし、携帯Webアプリの脆弱性に対してサブスクライバーIDを頼りに対策するサイトが増えると、廃止すべき仕組みを廃止しようにも廃止できなくなってしまうのが問題だからだ。
そしてもうひとつ理由がある。
WEB+DB PRESS誌の記事では、次のようにも書かれていた。
端末認証
登録が必要なサイトの場合,利用する際にはログインが必要です.ID/パスワードを毎回入力するのでは,携帯の場合では特に面倒です.
そこで携帯ならではの認証方法として,現在の端末では取得が容易にできる端末自体の情報(端末ID)を利用します.
携帯サイト開発 実践テクニック 2007, 技術評論社 WEB+DB PRESS Vol.37, p.126
これに対し私は2007年2月23日の日記「携帯電話向けWebアプリの脆弱性事情はどうなっているのか」で次のように書いた。
そもそも、「ID/パスワードを毎回入力するのでは携帯の場合では特に面倒です」などといって、端末IDをパスワード代わりにしてはいけない。端末IDは他のサイトにも同じものが送信されるのだから、パスワード代わりになどならない。
これはひとつには、同日記の脚注1にも書いていたように、この記事には、キャリアのIPアドレスからのアクセスであることの確認の話は書かれていなかったことも問題であるわけだが、もうひとつ、次の理由がある。
SSLの利用を必要としているサイトを想定してみる。携帯電話でもSSLは利用されている。携帯電話のWebにおいてどこに盗聴のリスクがあるかというと、キャリアのゲートウェイからWebサーバまでの通信路が主であろう。そこに本当に盗聴のリスクがあるのか? という疑問を抱く人がいるかもしれないが、携帯電話でSSLが必要とされているサイトがあるのは事実である。
その場合に、サブスクライバーIDをパスワード代わりに用いるのは明白に脆弱性と言える。なぜなら、図2のように、通信路上の盗聴者はパケットを改竄するなり、あるいは独自のIPパケットを送出することにより、キャリアのIPアドレスからの任意のサブスクライバーIDを送信することができてしまうからだ*8。
これができてしまうのは、サブスクライバーIDが攻撃者に既知となるためである。
こうした事態を避けるには、ランダムに生成されるセッションIDをcookie(secure属性を指定した)に入れてSSLで通信すればよい。PCのWebでは普通そのように実装されている。
問題は、cookie機能がサポートされていない、NTTドコモなどの携帯電話であろう。iモードでは、cookie機能がないため、URLにセッションIDを入れることが広く行われているようだ。それは、前述の(B)および(a)のタイプの構造であり、session fixationに弱い。
NTTドコモは早くcookieをサポートするべきだ。携帯Webの危うさは、NTTドコモがcookieをサポートしないことが主要因ではないのか。EZwebと同様に、ゲートウェイにcookie機能を作りこめば、全端末に対応できるのではないのか。
*1 このサイトではユーザ名が存在しないので、EZwebのサブスクライバーID (最近では「EZ番号」と呼ばれるようになった)がユーザIDとして用いられていると思われる。
*2 図1で言えば、User(1)が攻撃者でUser(2)が被害者とすると、(User(1)のloginは省くことができ、)User(2)がログインしたころを見計らって、User(1)がviewの操作をするとUser(2)の個人情報を意図的に盗むことができてしまう。
*3 上記文献の脚注6には、JRunでは存在しないセッションのセッションIDが指定されたときだけこの挙動をするとされているが、他の製品ではそうではない(いつでも受け入れてしまう)ことが示唆されている。
*4 EZwebでは、cookieをサポートしているので、この対策を採用できる。
*5 偶然に有効なセッションIDに一致してしまう確率はゼロではないが、当てずっぽうのセッションIDでセッションハイジャックできる確率と同じはず(セッションIDが暗号学的に安全な擬似乱数生成器で生成されていれば)なので、無視できる。
*6 domain属性の異なる同名の「JSESSIONID」cookieがリクエストに送られてくることになるので、全部をサーチして有効なものだけ使うようにするか、あるいは、セッションを開始する際に、domain属性が「.co.jp」などのcookieを消すSet-Cookieをするようにしておく対策が考えられる。
*7 これにより、セッションハイジャック全般を防止できるわけだが、それは、そもそもセッションIDすらいらないことを意味する。サブスクライバーIDをセッションID代わりに使えばよい。つまり、セッションオブジェクトをサブスクライバーIDで参照するように、Webアプリサーバを作ればそれが可能である。
*8 これができないというのなら、SSLもいらない。
なんだろうけど、携帯電話のいわゆる端末固有情報 (ICC等) が専らよろしくないのは、ユーザがどのページにアクセスしても同じIDが送信されるということがある。いきなり廃止という議論をするのではなく、とりあえずURLとIDの値のハッシュをとってそれを端末が送るように..
EZwebサイトでSession Fixation被害発生か?より。 この記...