「WWWサイトにアクセスして自分の個人情報を表示・更新しようとすると,画面に他人の情報が表示される」という現象が発生していたことが,2002年9月末から10月にかけて相次いで公表された。今年になって多発したWWWサイト上の個人情報ファイルが閲覧可能になっていた,といった情報漏えいとは違うタイプの事故である。

 アンチウイルス・ソフト大手のトレンドマイクロでは「会員契約更新サイト」で,「直前にログインしていたユーザーの情報」が表示されるという現象が発生した。同社には,9月3日から9月4日にかけて,上記のような現象に遭遇したというメールが,10人のユーザーから送られてきた。この現象は,「想定以上のアクセスにより暗号化の処理が間に合わず,直前にログインされていた方の情報が,まれに次のお客様の画面に誤って表示された」(同社 広報部)という。

 10月10日には,リクルートが「イサイズじゃらん宿予約サービス」で,他人の予約情報が表示されてしまうという現象が起きていたことを発表した(関連記事)。「宿予約の完了時に表示される画面について,特定の操作をされたお客様の予約情報が,同じタイミングで予約されている他のお客様に表示される可能性があった」(リクルート)。リクルートによれば,この現象は2000年11月11日のサービス開始時から発生していたと考えられる。同社で,把握可能な過去2カ月間の履歴を調査したところ,65名の予約情報に,第三者が意図せずアクセスしてしまっていたという。

知識不足や不注意によって簡単に発生し得る

 なぜ,このような現象が起きるのだろうか。トレンドマイクロ,リクルートとも,問題が発生したメカニズムについては「セキュリティ上の問題なので,詳細は公開できない」と回答した。そのため,両サイトの内部で何が起きていたのか,その詳細は不明である。

 しかし,インテグレータなどに取材すると,多くの専門家が「このようなバグは,プログラマの知識不足や不注意によって簡単に発生し得る」と指摘する。多くの開発者にとって決して対岸の火事ではない。

 日本IBMでは,このような「他人の情報が表示される問題」を「別人問題」と呼んでいる。日本IBM ソフトウェア事業部 SWテクニカル・サポート&サービス WebSphere技術部 ITスペシャリスト 田中孝清氏は「様々な状況で起き得る」と警鐘を鳴らす。

 典型的な状況は,マルチスレッドによる並列実行を意識せずに,サーバー・サイドJavaのプログラムを書いてしまうケースだ。サーバー・サイドJavaのプログラムであるJavaサーブレットは,マルチスレッドで動作しており,複数のメソッド(手続き)が同時に実行される。このことをうっかり忘れて,個人データを格納した変数が,複数のスレッドから共有されるように記述してしまうと「他人の情報が表示される」という現象が発生してしまう。

 共有されるように記述するのは簡単だ。例えば,変数を宣言する際にstaticというキーワードを宣言するだけで,変数は共有されてしまう。他のユーザーの処理が変数を書き換えてしまうために,誤ったデータが表示されるだけでなく,誤ったデータによる更新が行われる場合もある。

 多くのプログラマにとっては「そんなことは承知している」という,きわめて初歩的な注意点である。しかし,告白すると,記者は最初「他人の情報を表示する」という現象がなぜ発生するのか,全く見当がつかなかった。そんなことがあり得るのだろうか,とさえ思った。教えられて初めて,「スレッド・セーフ」という言葉とこの現象が結びついた。私のように,このような問題の可能性について意識していない方もいらっしゃるかもしれない。そのような方に,ぜひ注意していただきたい。

グローバル変数の使用やキャッシュ・サーバーなど様々な原因がある

 さらに,この「別人問題」は,マルチスレッドのほかにも様々な原因により発生する。決してJava固有の問題ではない。「同じ問題はPerlでも起き得る」と,オン・ザ・エッヂ 執行役員上級副社長 宮川達彦氏は言う。

 WWWサーバー・ソフトApcheのモジュールとしてPerlを動作させるmod_perlでは,Perlインタプリタを1回のアクセスごとに起動するのではなく,常駐させておくことで性能を向上させている。しかし,そのためブラウザからのアクセスを処理したあとも,Perlプログラム中の変数にはデータが残っており,次のアクセスでそのデータを参照することができる。データが個人情報であれば,前にアクセスしたユーザーの情報が次のアクセスに表示されてしまうという可能性がある。

 「このような状況を避けるためには,リクエストに依存する情報をグローバル変数に格納することは絶対に避けなければならない。また,strictプラグマや,-wスイッチを使えばこのような問題を発見することができる」(宮川氏)

 日本IBMの田中氏が調査した,あるケースでは,キャッシュ・サーバーによるWWWページのキャッシングが原因になっていた。

 Webアプリケーションでは,WWWサーバーが一人のユーザーによる一連のアクセスを一つのセッションとして認識できるように,セッションIDが発行することがある。一般に,セッションIDはCookieやURLなどに埋め込まれる。ここで,セッションIDをURLに埋め込み,そのURLをリンクとしてHTMLに含める場合に問題が起こり得る。WWWサーバーの負荷を軽減するために設置したキャッシュ・サーバーが,ユーザーA向けのセッションIDを埋め込んだリンクをキャッシュしていると,別のユーザーBが,同じセッションIDを使ってユーザーAの個人情報にアクセスしてしまう。

 また,イーシー・ワン ストラテジック・ソリューション本部 cBankソリューショングループ グループマネージャー 佐藤純一氏は,さらに高負荷でしか発生しない問題を修正したことがある。

 ある大規模ECサイトで,他のユーザーの情報が表示されるという現象がまれに発生した。解析を依頼された佐藤氏らが調査したところ,ユーザー情報を格納するオブジェクト(Stateful Session Bean)に,使用前に初期化されていないものがあることを発見した。必ず初期化するようにしたところ,現象は再現しなくなった。「高負荷時にだけ, オブジェクトが新しく作成されるのではなく既存のオブジェクトが再利用され,残っていたユーザー情報が表示されたと考えられる」(佐藤氏)

テスト担当者やプロジェクト・マネジャにも知ってほしい

 なぜ,このような「他人の情報を表示する」バグがテストで発見されず,本番で発生してしまったのだろう。

 その原因は,テストでの発見が非常に困難という点にあると,記者は考えている。単に仕様書を満たすかどうかのテストを行っているだけでは発見できず,複数のユーザーが,同時に同じ操作を行うようなテストでなければ発見できない。共有されている変数が,一時的に使用されるテンポラリ変数であったりする場合,数十ミリ秒の間に複数のユーザーが操作した時に初めて問題が発生する,という場合さえある。

 テストで問題を発見するためには,このような盲点を知り,それを想定したテストを実施する必要がある。テスト担当者やプロジェクト・マネジャにも,この「別人問題」を広く認識してもらいたいと考えている。

 今回の取材にあたって,リクルートからは「要因を公表することで,他社などで同様のトラブルが発生する可能性もある。こういう要因が広くあると報道することが,危険性をはらんでいることも考慮していただきたい」(同社 広報室)という趣旨のご意見をいただいた。言うまでもなくリクルートもトレンドマイクロも,問題を隠しているわけではない。問題の範囲から,過去の記録について調査しきれない時期があることまで,包み隠さず公表しておられる。その上でのご指摘は,重く受け止める必要がある。

 しかし,記者は悩んだ末,やはり広く知っていただくべきだと判断した。今回の問題は,悪用しようとして悪用できるものではない。WWWサイトのユーザーが問題を知ることによるリスクはそれほど大きくない。それよりも,この問題を知らなかった開発者やサイト運営者が問題を認識することのメリットの方が大きいと考えている。もちろん,記者と異なる考えをお持ちの方もおられると思う。ご意見をいただければ幸いである。

(高橋 信頼=日経オープンシステム)

参考情報日経オープンシステム2002年12月号特集「テストの死角」