🍪

クッキーの危険性(ダイエットではなくセキュリティの話)

2023/01/05に公開

現在多くのアプリケーションでは、クッキーを用いたセッション管理をしています。
認証結果の保存などセキュリティ上重要な役割を果たしており、
食べ物のクッキーのカロリー問題も大事ですが、今回はWebにおけるcookieにどのような問題があるのか・どう防ぐのかを見ていきます。

なお、この記事は徳丸浩著の「安全なWebアプリケーションの作り方」を参考にしています。

🍪クッキーとは?セッション管理とは?

まずはセッション管理が何かを説明します。

例えば、TwitterなどでIDとパスワードを入力して一度ログインしたサイトにしばらくしてからもう一度アクセスした場合、IDとパスワードを入力しないでもそのまま入れますよね。
もしくは、ショッピングサイトで買い物をしている途中で、商品をカートに入れたままログアウトしたとします。しばらくしてから、もう一度同じショッピングサイトにログインしたら、カートの中の品物が消えずにしっかり残っています。

このようにIDパスワードや買い物状況などアプリケーションの状態を覚えておくことをセッション管理と言います。

そして、このセッション管理をHTTPで実現する仕組みがクッキー(cookie)です。サーバ側からブラウザに対して、「名前=変数」の組を覚えておくように指示します。

🥣クッキーの使い方

アプリケーションデータを保持する目的でクッキーそのものに値を入れることはあまりありません。
その理由は、

  • クッキーが保持できる値の個数や文字列長には制限があるから
  • クッキーの値は利用者本人には参照・変更できるので、秘密情報の格納には向かないから
    です。

なので、クッキーには「整理番号」としてセッションIDを格納しておき、実際の値はサーバー側で管理する、という方法が主流です。これをクッキーによるセッション管理と呼びます。主流はWebアプリケーション開発ツールにはセッション管理のための仕組みが提供されています。

🍳セッション管理でのやり取り

セッション管理がどのように行われているかを銀行窓口業務を例えに説明します。

客:お願いします。
受付:お客さまの整理番号は008です。口座番号と暗証番号をお願いします。
客:整理番号008です。口座番号は1234567、暗証番号は1111で本人確認をお願いします。
受付:本人確認いたしました。
客:整理番号008です。残高紹介をお願いします。
受付:残高は100万円です。
客:整理番号008です。口座番号2222に3万円振り込みをお願いします。
受付:振り込みました。

対話の中で整理番号と読んでいる数字はセッションIDです。客は受付に毎回整理番号を伝えていますが、これはブラウザーが自動的にクッキーをサーバーに送信することを真似ています。

悪用できてしまうやりとり

セッションIDには以下の3つの要件があります。

  1. 第三者がセッションIDを推測できないこと
  2. 第三者からセッションIDを強制されないこと
  3. 第三者にセッションIDは漏洩しないこと

これらが損なわれるケースを説明します。

ケース1 推測できる

この整理番号008は、前後の番号に変更することで、別人になりすますことが可能であり、次にそのやり取りを見て見ます。

悪客:お願いします。
受付:お客さまの整理番号は005です。口座番号と暗証番号をお願いします。
〜悪人は、整理番号が連番だと予測し、1つ戻し004に変更する。整理番号004の客は既に本人確認を済ませている〜
悪客:整理番号004です。口座6666に50万円振り込みをお願いします。
受付:振り込みました。

整理番号を変更するだけで、別人がまんまと送金することができてしましました。
このため、セッションIDは連番ではダメです。十分な桁の乱数を用いる必要があります。
乱数の質を上げるには、セッションIDを生成する際は、自作ではなく、Webアプリケーションの開発ツールで提供されるセッションIDを利用しましょう
メジャーな開発ツールは世界中の研究者が調査をしていて、もし生成に問題があれば脆弱性として指摘されて素手の改善されているはずだからです。一方自作したものでは、脆弱性が混入していたケースが多々あります。
セッション管理機構は自作しないことが重要です。

ケース2 IDを強制される

また例をあげます。

悪客:お願いします。
受付:お客様の整理番号はuhkoiu943knhui0875nk29hです。口座番号と暗証番号をお願いします。
〜悪人は受付の元を離れ、客が来るのを待つ。客が銀行に入ると、悪人が銀行員のふりを敷いて客に話しかける〜
悪人:お客様の整理番号はuhkoiu943knhui0875nk29hです。
客:わかりました。
〜客は窓口に行く〜
客:整理番号uhkoiu943knhui0875nk29hです。お願いします。
受付:口座番号と暗証番号をお願いします。
客:整理番号uhkoiu943knhui0875nk29hです。口座番号は12345、暗証番号は1111で本人確認をお願いします。
受付:本人確認しました。
〜客が本人確認されたタイミングで悪人も窓口に行く。整理番号uhkoiu943knhui0875nk29hの口座は本人確認が完了しているステータスとして覚えられている〜
悪人:整理番号uhkoiu943knhui0875nk29hです。口座番号7777に70万円振り込みをお願いします。
受付:振り込みました。

これが正規利用者に対してセッションIDを強制する攻撃で、「セッションIDの固定化攻撃」(Session Fixation Attack)と呼ばれる手法です。
この脆弱性を直すために、上記のやりとりをこのように訂正します。

(上記と同じ流れで、客が入ってきたところから再現)

〜客が銀行に入ると、悪人が銀行員のふりをして客に話しかける〜
悪人:お客様の整理番号はuhkoiu943knhui0875nk29hです。
客:わかりました。
〜客は窓口に行く〜
客:整理番号uhkoiu943knhui0875nk29hです。お願いします。
受付:口座番号と暗証番号をお願いします。
客:整理番号uhkoiu943knhui0875nk29hです。口座番号は12345、暗証番号は1111で本人確認をお願いします。
受付:本人確認しました。お客さまの新しい整理番号はeugk237jkkuc94lkyhuo0dです。
〜客が認証されたタイミングで悪人も窓口に行く。〜
悪人:整理番号uhkoiu943knhui0875nk29hです。口座番号7777に70万円振り込みをお願いします。
受付:本人確認されていません。口座番号と暗証番号をお願いします。

認証されたタイミングで整理番号(セッションID)を変更したため、攻撃者が元の整理番号で振り込もうとしても本人確認はされていない状態になっています。このように、セッションIDの固定化攻撃は、認証後にセッションIDを変更することで防げます

ケース3 セッションID漏洩

セッションIDが漏洩するとなりすましができるので、漏洩しないように対策が必要です。
セッションID漏洩の主な原因は以下があります。

  • クッキー発行の際の属性に不備がある
  • ネットワーク的にセッションIDが盗聴されている
  • クロスサイト・スクリプティングなどアプリケーションの脆弱性により漏洩する
  • PHPやブラウザなどプラットフォームの脆弱性により漏洩する
  • セッションIDをURLに保持している場合は、Refererヘッダから漏洩する

ネットワーク的に漏洩する可能性があるのは、ネットワークの経路上に盗聴の仕掛けがしてある場合です。どこに盗聴の仕掛けがあるかは外部からはわかりませんが、公衆無線のLANなどの原理的に盗聴のしやすい環境では、盗聴の危険性が特に高くなります
セッションIDをネットワーク盗聴から保護するにはSSLによる暗号化が有効ですが、クッキーを発行する際の属性指定には注意が必要です。

🍫クッキーの属性

クッキーを発行する際にはさまざまなオプションの属性を指定できます。主な属性は下記の通りです。

属性 意味
Domain ブラウザがクッキー値を送信するサーバーのドメイン
Path ブラウザがクッキー値を送信するURLのディレクトリ
Expires クッキー値の有効期限。指定しない場合はブラウザの終了まで
Secure SSLの場合のみクッキーを送信
HttpOnly この属性が指定されたクッキーはJavaScriptからアクセスできない

この中で、セキュリティ上重要な属性は、Domain、Secure、HttpOnlyの3つです。

Domain属性

クッキーは、デフォルトではクッキーをセットしたサーバーにのみ送信されます。セキュリティ上はこれが最も安全です。が、複数サーバーに送信されるクッキーを生成したい場合もあり、その場合にDomain属性を使います。

Domain=hoge.jpと指定したとします。その場合は、a.hoge.jpやb.hoge.jpにはクッキーが送信され、a.hoge.comはドメインが違うので送信されません。

Domain属性を指定しない場合は、クッキーを生成したサーバーにのみクッキーが送られます。従って、Domain属性を指定しない場合が一番クッキーの送信範囲が狭く、安全な状態と言えます。一方、Domain属性を不用意に設定すると脆弱性に繋がる可能性があります。
脆弱性となる例として、例えば、hoge.comがレンタルサーバーの事業者で、c.hoge.comとd.hoge.comがレンタルサーバー上で運営されているWebサイトであるとします。ここで、c.hoge.comサイトが発行するクッキーにDomain=hoge.comを指定したとします。そうすると、クッキーはd.hoge.comにも漏洩してしまいます。

このように、Domain属性は通常設定しないものと覚えておくと良いです。

Secure属性

Secureという属性をつけたクッキーは、SSL通信の場合のみサーバーに送信されます。一方、ついていない場合はSSL通信かどうかは関係なく、クッキーが常にサーバーに送信されます。
クッキーのSecure属性は、クッキーのSSL送信を保証する目的で指定します。

HttpOnly属性

この属性はJavaScriptからアクセスできないクッキーを設定するものです。

クッキーとして格納されたセッションIDを盗み出す攻撃の典型例は、クロスサイト・スクリプティング攻撃によりJavaScriptを悪用してクッキーを盗み出すものです。そこで、HttpOnly属性を指定するとJavaScriptによりクッキーを盗み出せなくなります
ただし、クロスサイトスクリプティングをこの属性で完全に防ぐことはできません。攻撃を難しくすることはできます。また、HttpOnly属性をつけることによる悪影響は通常ないのでセッションIDにはHttpOnly属性をつけると良いです。

🥛まとめ

クッキーを使ったセッション管理とは何なのか・そのセキュリティ問題についてまとめました。
基本的なところしかまとめていませんが、どのような場合が危険でどのように防げるかをインプットできたと思うので、セキュリティ問題を考える引き出しとしてこの記事を使えるようにしたいと思います。

Discussion