自動ログインの実装に見る、Cookieの取扱で注意すべき点


CakePHPのプロジェクトに自動ログインの機能を入れてみましたが、その際に使ったライブラリが、示唆に富むものでした。

まず、Cookieとは

ステートレスなHTTP

Webを支えているHTTPですが、HTTP/1.1までの基本構造としては1、「1つのリクエストに対して1つのレスポンス」を行うという、ステートレスなプロトコルとなっています。

とはいえ、ログイン機能、ショッピングカートなど、Webサービスを提供する上では、状態管理が欠かせなくなってきます。そこで登場したのがCookieで2、識別用の情報をリクエストごとに送信することで、ステートレスなHTTPで状態管理を実現しています。

Cookieの属性

Cookieには、「キー」、「値」以外にもいくつか属性があります。

  • domain属性…クッキーが有効になるドメインを指定します。.example.co.jpのように、サブドメインを一気に指定することもできます。
  • path属性…クッキーが有効になるパスを指定します。
  • max-age属性/expires属性…クッキーの有効期限を指定します(何も指定しなければ「ブラウザを閉じるまで」になります)
  • secure属性…HTTPSにしかこのクッキーを送信しないようにします。
  • httponly属性…JavaScriptのdocument.cookieでこのクッキーを読み取り不能とします。

自動ログインに必要なこと

長期間に渡ってログインを不要とするためにセッションの有効期間を伸ばしてしまえば、セッションキーが盗まれるセッションハイジャックのリスクも高まります。ということで、「自動ログイン」は以下のような挙動になります。

  • セッション用のキーとは別に、長期間持たせるログイン用のCookieを用意する。
  • 適切なタイミングでそのCookieをチェックして、あったらログイン処理を行ってセッションを展開する

考える要素としては、以下のようなものがあります。

  • 発行したトークンの(サーバサイドでの)管理方法
  • どのような形でブラウザにCookieとするか
  • 自動ログイン用のCookieのチェック方法

実際の挙動

今回使ったのは、Beskhue/CookieTokenAuthというライブラリです。以下、どのような挙動か追いかけていきました。

ログイン用クッキーの発行

まず、保存されるデータですが、DB定義のSQLにあるように、「ユーザーID」「トークンID(series)」「トークンのハッシュ値(token)」「有効期限」を記録しています。ここで、ユーザーID頼みにせずに別なキーを入れることで、1つのアカウントから複数の端末での自動ログインを可能としています。

トークン値の意味について

自動ログイン用のキーとしてパスワードからハッシュを生成する方法では、ユーザーがパスワードを変えない限り同じキーが使われ続けるので、無効化する手立てがなくなってしまいます。別に自動ログイン専用のトークンを作ることで、期限切れでDB側を消せば無効化できるなど、セキュリティ的にも管理をやりやすくしています。

そして、『秘密の国のアリス』に「もしも、平文に人の命がかかっているなら、鍵にも人の命がかかっていることになるのです。」とあるのと同様に、「ログインできるトークン」は、「ログインに必要なユーザー名+パスワード」とほぼ同等の価値を持ちます。幸い、このトークンは検証さえできればいいので、パスワード同様にハッシュ化して格納すればもとの値を取ることがほぼ不可能となります。

実際の発行

発行処理はCookieTokenComponent#setCookieソース)で行っています。データベースに必要な値をセットして、Cookieを特定のパスだけ(後述)に限定した上で、さらにCakePHPの機能でAES暗号化してユーザーに送信しています。secureやhttponlyは適宜設定が必要そうですが、こういうクッキーの場合は必要不可欠、とも言えます。

自動ログインのキーを送るのは、これを意識的に呼んだ場合に限られます。基本的には、ログインごとに1回、となるでしょう(トークンはハッシュ化しているので、再送はできません)。

自動ログインのチェック

自動ログイン対象かどうかのチェックは、CookieTokenAuthenticate#authenticateで行っています(ソース)。まず、セッションデータで「自動ログインのチェック済み」かどうかを確認して、すでにチェックが終了していれば何もしません。

チェックが必要となれば、いったん/auth/cookie-token-authにリダイレクトさせます。先程行ったクッキーの設定で、ここでしか自動ログインのを受け取れないようになっている関係上そうなりますが、逆にここへ来なければクッキーを送信しないので、通信路の盗聴に対しても安全性を高めています。正しいクッキーが来ていればログインを行って、自動ログインのキーを更新して一件落着となります。


  1. HTTP/2ではサーバとクライアントの間でセッションを構築するようになります。 

  2. もちろん、「URLに識別情報を埋め込む」という手段もなくはないのですが、ブックマークやリファラーなどで識別情報まで流出してしまう、第三者が同じURLにアクセスできるなどセキュリティ上よろしくないので、ほぼ使われません。