【PHP】セッションIDをトークンとして使うべきではない

PHP

よくセッションIDをトークンとして利用しているWebサービスを見かけることや、そのような解説をしているブログ記事を見ることもあります。

(この時点でのトークンとは、「しるし」という意味で使用していて、アクセス元が正規サイトであることを確認するために用いることを前提としています。)

ですが実際セッションIDをトークンとして使用すると場合によっては罠サイトがユーザーの個人情報を無断で収集することもできるからです。

なぜ使うべきではないのか

それは、セッションIDの役割について理解することですぐにわかります。

セッションIDはユーザーの情報を保持するためのキーであり、セッションIDとデータが結び付けられています。

つまり、セッションIDさえ分かればそのデータを結びつけることが可能になるということです。

例えばこのような状態です。

<img src="./image/put_image?key=02&token=<?=session_id()?>">

これはphpで表示する画像を切り替える例です。

この場合外部から読み込まれないようにするためか、トークン(セッションID)により自分のサイトかどうかを判断しているようです。これが出力されるとこのようになります。

<img src="./image/put_image?key=02&token=mysessionid">

(mysessionid = 実際のセッションID)

つまり、ページにセッションIDが公開されている状態になります。

例えばこれを、Ajax等で罠サイトがCookie付きでこのページにリクエストしたらどうなるでしょうか。

もちろん、セッションIDが入っているページが返されます。

これを解析することで簡単にセッションIDを抜き出すことが可能です。

例えばこのように盗んだセッションIDを自身のブラウザにセットしてサイトにアクセスすれば、もしそのユーザーがログインしているのならばログインができてしまいます。

クレジットカード情報が保存されていても見れてしまいます。

たとえ二段階認証を設定していたとしてももうログイン済みの状態で入ってしまうのですから、意味はありません。

なので、このようなことにならないように、セッションIDをトークンとして利用することはお勧めしません。

「ID」を生成する

セッションIDと別のIDをランダムに作成し、それをセッションに保存することで認証する方法です。

まず、ページにアクセスしてユーザーがトークンを持っていない場合次のコードでトークンを生成し、セッション内に保存します。

$_SESSION['token']=substr(str_shuffle('1234567890abcdefghijklmnopqrstuvwxyz'),0,random_int(5,15));

これは簡単な例で、お勧めはしません。

なぜなら、完全にランダムではなく、生成するトークンに同じ文字を含むことはない為、パターンが限られます。ですが5文字から15文字の間で生成するようにして、パターンを増やしています。

このコードのまま使用する場合、最大20文字までにすることをお勧めします。文字数を長くしすぎるとパターンが一定のものになり、逆に推測されやすくなります。

そしてこのSESSION[‘token’]を使用することで完全にランダムであり、かつセッションIDとは関係ない文字列を生成することができます。

最後に

セッションIDをトークンとして使用している場合、なるべく上記のように変更することをお勧めします。

また、上記のトークンも一定時間おきに更新することをお勧めします。