未検証なので信憑性はないが、iモードにおけるgmailのセッション管理を解析してみた

1. iモードにおけるSSL事情
iモードSSL通信中、下記のどの方法でもユーザーを一意に識別する情報を取得する事ができません。

・utn
・NULLGWDOCOMO
・guid=ON
cookie(iモードは未対応)

そのため、iモードSSL通信中にユーザーを一意に識別したい場合(*1)はURLにsession_id=*****というようなセッション情報を付加して引き回さないといけません。しかし、そうするとセッション情報が付加された状態のURLが何らかの理由で他人の手に渡った場合(*2)、セッションハイジャックの恐れが出てきます。

*1 ECサイトの決済画面など
*2 ユーザーがメールで他人に送ってしまったり、通信が盗聴されたり...


2. gmailの不思議
まず先に結論を述べておくと、iモードgmailを閲覧した時のSSL通信中のURLを、他の端末に転送してもセッションハイジャックはできません。強制的にログアウトされてしまいます。

1で述べたように、iモードではSSL通信中はURLにセッション情報を付加する以外の方法では、ユーザーを一意に識別する事はできません。それにもかかわらず、URLを盗んだセッションハイジャックが不可能ということは、何かしらの方法でリクエストを送ってきた端末がセッション情報の正当な持ち主かどうか検証できる手段を講じていることが伺えます。

gmailは携帯電話からでも閲覧ができるようにマルチプラットフォーム対応されており、私が持っているiモード端末でもメールの確認をすることができます。gmailでは全ての画面においてSSLが適用されており、gmailのログイン後のURLを見ると、何やら複雑なランダム文字列が並んでいて、長さは256バイトにも及んでいます。

私は最初、携帯サイトにしては異常な長さのURLにしておくことで、ユーザーがメールで送信することを防ごうとしているのかと思いました。長さにかかわらず、ログイン後のURLを別端末に送信したらセッションハイジャックできてしまうのだろうと思い、別端末にURLをメールで送りセッションハイジャックの実験を行ってみました。しかし、予想外にも別端末でアクセスすると強制的にログアウトされてしまい、URLを盗み出してもセッションハイジャックできないということが判明したのです。


3. ユーザーを一意に識別している手段の考察
SSL通信中にユーザーから得られる情報と言えば、UserAgentの情報くらいしかありません。私は、URLの中に端末の機種情報が含まれていて、セッションハイジャックしようとした端末の機種が異なっていたら強制ログアウトになるのだろうかと考えました。しかし、それだと同じ端末であればセッションハイジャックできてしまうことになるので少しお粗末な感じです。

とは言え、念のために実験を行ってみました。ログイン後のURLをメールで自分宛に送信して、メールに記載されたURLに接続するという実験です。行った結果、予想通り強制ログアウトされました。UserAgentの情報を使ってごにょごにょというのはやっていないようだということが分かりました。

やってみたあとで気づいたのですが、実はこの実験でとても重要な事実に気づく事が出来ました。同じ機種の端末であってもセッションハイジャックできないことが証明されただけでなく、本人の端末でもログアウトになるということから、端末を一意に識別はしていない、ということが判明したからです。

補足:iモードでは「Internet」->「URL入力」とメニューをたどってURLを直接指定してアクセスする方法があります。メールへの転送だけではなく、ログイン後のURLを直接叩いてページを開く場合も強制ログアウトになります。


4. 仮説
端末を一意に識別しているのではないということが分かりました。となると、何の情報を使ってURLをリクエストした端末が、URLの正当な持ち主かどうかを検証しているのでしょうか?

自分のURLを自分宛にメールで送るという実験の一件から、私は何となくSSL通信が怪しいと目をつけました。SSLでは鍵の交換が完了した後に暗号化された通信路が確立されますが、リクエストの度にいちいち鍵交換をやっていなさそうだと思い、鍵交換が完了したあとにはクライアントとサーバー間でステートフルな状況があるのではないかと考えました。ステートフルな状況、それはユーザーを一意に識別する事が可能な状態だと言えます。

調べて行くと、案の定そういった情報を見つける事が出来ました。SSL通信には、SSLセッションIDというのがあって、暗号化された通信路を確立した以降は、確立するまでの同じ作業(鍵交換)を省略するため、サーバーとクライアント間でSSLセッションを保持するための情報を互いに持つようです。

gmailでは、ログイン時にSSLセッションIDとユーザー情報を紐付けているのではないでしょうか。
そうしておくことによって、クライアントから送信されたSSLセッションIDからユーザーを一意に識別する事ができ、リクエストされたURLを処理すべきか判断できます。逆に、送信されてきたSSLセッションIDが新規作成のもので、それにもかかわらずログイン後のURLがリクエストされていた場合は'あり得ない状況'として判断ができ、不正なアクセスとして強制ログアウトにできます。


5. perlの実装例(未検証)
未検証なのですが、言っている意味としては以下のような実装になると思います。mod_perl環境下での動作を想定しています。

CPANモジュールを漁って、SYNOPSYS見ただけなので動くかどうかも分かりませんが、イメージだけでも分かって頂けるとうれしいです。

#!/usr/bin/perl

use strict;
use warnings;
use Apache2::Access ();
use Apache::SSLLookup;

my $ssllookup = Apache::SSLLookup->new($r);
my $value = $ssllookup->lookup_var('SSL_SESSION_ID');

# $value の値をDBなどで引き、存在すればそこからユーザーを
# 特定する。ない場合は不正アクセスと見なして強制ログアウト。

(参考情報)
SSLセッションIDをperlコードで取得するためのモジュール
http://search.cpan.org/~geoff/Apache-SSLLookup-2.00_04/SSLLookup.pm

・mod_sslに'SSL_SESSION_ID'という環境変数(Envaironment Variables)があること
http://httpd.apache.org/docs/2.0/mod/mod_ssl.html

6. 最後に
正当な証明書をもったSSL通信可能なサーバーがないので、残念ながら上記の仮説は未検証です。いずれは自分で検証してみたいのですが、どなたか環境がある方が先に試してくださったりすると、うれしいです。

SSL通信時に端末を識別する事ができないiモードの仕様は、開発者にとっては苦しい問題でありますが、googleは何らかの手段でセキュアな実装を可能にしています。この仮説が正しければセキュアなサイトを作るための良いノウハウになるのではないかと思います。

一番うれしいのはSSL通信中でも、一意に端末を識別できる情報を取れる事ですが、iモード端末の後方互換性などを考えると面倒な時代はまだまだ続きそうです。