Webアプリ作るなら必須!Cookieを徹底調査

Cookieについて改めて勉強しました

んやりと理解していたCookieを正しく知ろうと思い立ちいろいろと検索をしていたらCookieとCacheの違いを説明している記事が多く、純粋にCookieについて教えてくれる記事が少なそうだったので書くに至りました。

勉強して思ったのは、Cookieを正しく知らないでWebアプリケーションを開発することは非常に危険だということです。Cookieの理解が曖昧だとセキュリティ問題に繋がる可能性が高いです。 Cookie起因のWebサービスの脆弱性は、ユーザーのログイン状態が奪われるなど影響が大きく、万が一、発生すると会社の信頼がどん底に落ちてしまいます。 Cookieについて正しく理解して防げる脆弱性は潰していきましょう!

本記事では、Cookieとは何か、どんな使われ方をするのか、Cookieが絡むセキュリティ問題について書いています。

RFC6265に世界標準のCookieの仕様が載っているので適宜参照してください。

まず、ひとことでCookieとは?

ステートレスなHTTP通信でも一人ひとりに違う内容のページを表示させたり、前回のアクセスの続きとして対応することを可能にするために個人を識別する会員証のように扱われ、 Webサーバーからユーザーのwebブラウザに送られる、ユーザーのデータを保存しておくためのファイルのことです。

ステートレス:サーバーなどのシステムが現在の状態を表すデータ(ログイン状態等)を保持せず、入力の内容によってのみ出力が決まる方式です。同じ入力に対する出力は常に同じになります。

(出典)ステートレスとは - IT用語辞典 e-Words

どんな使われ方をするのか?

個人を識別できることから以下の利用方法が代表的です。

  • Webサービスへのログイン状態の保持
  • ECサイトの買い物かご機能
  • 広告の最適化

Cookieはログイン状態の保持に使われることから攻撃者は、そのログイン状態を奪いにかかります。ログイン状態を奪われるとあなたのログインしているWebサービスを勝手に攻撃者に使われることになります。

Cookieの属性

Cookieはサーバーからブラウザへと送信され、Cookieをブラウザ上でどのように扱ってほしいか指定する「属性」を付与することができます。 注意点としては、ブラウザからサーバーへのリクエストでは、属性を指定できません。つまりCookieの属性が指定していできるのは、サーバー -> ブラウザ の一方向のみです。

Path

パス毎に異なるセッションIDを発行したいというときに有効な属性です。例えば、pathによってサービスが違う場合に使えます。 ただし、異なるパスへのCookie付与はできてしまうため、安全性は保証されません。

Domain

デフォルト状態であるこの属性を指定しないCookieが一番安全と言われています。

CookieのDomain属性は 指定しない が一番安全

Domain属性を指定しないCookieは、Cookieを発行したホストのみに送信されます。サブドメインへは送信されません。 デフォルト状態が送信される範囲が最も狭く安全であると言えます。

逆にDomain属性を指定すると、サブドメインを含むホストへ送信されます。

Domain=hoge.com を指定したCookieは、foo.hoge.comへも送信されます。 Domain属性なしのCookieは、hoge.comにしか送信されません。

Secure

ブラウザからサーバー間の通信がHTTPSの場合のみCookieも一緒に送信されます。 もしCookieをセッション情報の管理使用する場合は設定必須の項目です。 万が一、この属性を付与せずにセッション管理に使っていると暗号化されていない平文でリクエストが送信されるのでセッション情報が盗聴される可能性があります。

Max-Age

クッキーの残存期間を秒数で指定でき、例えばMax-Age=1000であれば1000秒後に消滅します。 負の値を指定すると、最も過去の日付を指定したことになります。 指定しなければ、ブラウザが終了するとCookieが削除されます。

Expires

有効期限が切れる日付・時刻を指定します。 指定しなければ、ブラウザが終了するとCookieが削除されます。 この属性を指定するとブラウザを終了しても認証状態を維持することができます。

Max-AgeExpiresの違い

有効期限を指定する点は似ていますが、Max-Ageが秒数指定、Expiresが日時指定であることが大きく違います。 また、Max-Age Expires が両方設定されているとMax-Ageが優先されます。Max-Age > Expires

HttpOnly

JavaScriptから参照することができません。基本的にセッションIDをJavaScriptから読み取らせる意味は無いので指定したほうがいいでしょう。 この属性を指定することでXSSなどで悪意のあるスクリプトによって値が読み取られることを防げますが根本的な対策になるわけではありません。

SameSite

この記事を執筆時点で、RFCになっていないが、既に全ブラウザで実装されているのが、SameSite属性です。 Cookieは、オリジンが合致するときに送信されますが、攻撃者によって乗っ取られたWebサイトからのアクセスでもあっても、ブラウザはそれを判別すること無く、Cookieを送信してしまいます。 要するに、CSRF(Cross Site Request Forgeries)Timing AttackというCookieの脆弱性をカバーする目的で作られたのが、SameSite属性です。

Strict(厳しい) 設定されたCookieは、他ドメインのサイトに一切送信されません。Cookieの使用を完全にブロックするため、最も強いセキュリティ対策が行えます。 <a>タグのリンクをクリックしたときのページが切り替わるGETアクセスであってもCookieは送信されません。

Lax(ゆるい) top-level navigation以外のリクエストにはCookieを付与しません。Strictよりも緩い設定となりますが、CSRFの対象からは外れます。

None(なし) 文字通り属性指定は無しです。

用語集

Cookieの脆弱性を狙った攻撃

クロスサイトスクリプティング(Cross Site Scripting, XSS)

HTMLの生成の実装に問題があるとXSSという脆弱性が発生します。この影響はたとえば、攻撃者がJavaScriptを実行してクッキーを盗み出しログイン状態を奪われることがあります。 これを防ぐためにCookieのHttpOnly属性を有効化します。そうすることでJavaScriptからクッキーを盗み出されることがなくなります。

しかし、この脆弱性はHTML生成の実装方法に問題があることがから発生している脆弱性なので、Cookieの属性を指定するだけでは十分な対策とは言えませんが、HttpOnlyを有効にするだけなのでしない他ないでしょう。 ここでは、XSSの具体的な対策方法に関しては、Cookieの学習からそれるので割愛しますが、おすすめの解説記事を紹介します。

ちなみに「徳丸本」とは、徳丸浩さんが書かれた体系的に学ぶ 安全なWebアプリケーションの作り方のことです。 Webアプリケーションのセキュリティを考える上では非常に勉強になる名著です。

CookieのSecure属性を指定しないことによる脆弱性

Secure属性とは前述したとおり、HTTPS通信ときのみCookieを送信する制限を設けるための属性です。Secure属性がついていないCookieは暗号化されずに送信されることがあり盗聴されてログイン状態を奪われる可能性があります。 WebアプリケーションでHTTPしか使っていないなら、まずはHTTPSにするところからはじめてCookieの属性にはSecure属性を付けましょう。

Cookieの間違った使い方

書き換えられたくないデータをCookieに保存する

ユーザーIDや権限情報などの書き換えられたくないデータはCookieに保存しないようにするべきです。

Cookieはブラウザから書き換えることができるので、Webアプリケーションが扱うデータの中でユーザーから勝手に書き換えられたくない(サーバーが意図しない)ものはCookieに保存するべきではないです。

Chrome拡張機能「EditThisCookie」 - クッキーを表示・編集

なので基本的には、セッションIDのみをCookieに保存するべきです。ユーザーIDや権限情報をCookieに保存することは脆弱性に繋がります。 Cookieは、サーバーをまたがって使用できるので、セッション維持には向いていると言えます。

サーバーから復元できないデータをCookieに保存する

簡単に言うとデータベースと同じようにCookieにデータを保存してはいけません。 Cookieはブラウザのローカル領域に保存されるので、端末が変わるともちろん同じCookieのデータは取得できません。また、Cookieはブラウザのセキュリティ設定によってはサーバーから送られてくるデータを保存できないこともあります。 例えばシークレットモードでブラウザを開いているとサーバーからのCookieへのデータ保存を無視することもあります。 なので、サーバーから復元できるデータ以外は保存することに向きません。

サイズが大きいデータをCookieに保存する

リクエスト時に常にCookieはヘッダとして通信に付与されるため通信量が増えます。もちろんリクエスト、レスポンスの両方の通信速度に影響を与えるので容量は厳しく制限した方が良いです。 RFC6265には、最大容量は4KB、ドメインごとに50Cookieまで、全部で3000Cookie程はブラウザは保存できるようにすべきと定義されています。 なので、その制限を破ると使えるブラウザが制限されてしまうので、開発中のアプリケーションのCookieのデータサイズに注意しましょう。

最後に

この記事を読んで、Cookieの基礎を理解して、Cookieを正しく使えないとWebアプリケーションに脆弱性を生むことを理解していただければ幸いです。

updatedupdated2020-05-232020-05-23