「安全なウェブサイトの作り方」 1.4セッション管理のまとめと補足。
セッションIDにまつわるセキュリティ問題の概観や復習にどうぞ。
前提
セッションとは
ステートレスなHTTP通信を基礎とするウェブアプリケーションにおいて、ユーザーとアプリケーションとのやり取りを補完するための仕組み。
セッションIDとは
ユーザーがログインを行うと、サーバーはセッションIDを発行し、ユーザーとセッションIDを紐付けて記憶する。
また、ログインに対するレスポンスとしてセッションIDを返し、通常はユーザーのブラウザのCookieに保管される。
次にそのユーザーがサーバーに対して別のリクエストを行った際、セッションIDが一緒にサーバーに送信される。
そうすることで、サーバーはセッションIDからどのユーザーなのかを識別することができる。
つまり、セッションIDを用いることで毎度ログインせずにサーバーとのやり取りを行うことができるようになる。
セッションIDとセキュリティ
サーバーは「セッションIDがabcde
の人は、ユーザーID12345
の人だ」という紐付けをしているので、
セッションIDが第三者に盗まれるとなりすましができることになる。
セッションIDが盗まれることをセッションハイジャック
と呼ぶ。
これを防ぎましょうというのが本題。
セッション・ハイジャックの手口
防ぐためには相手の手口を知ることから。
手口1 : セッションIDの推測
セッションIDが連番や一定の規則をもとに作成されるようになっている場合は容易に推測が可能。
例えば、自分で2つアカウントを作成し、1つ目のセッションIDが12345
、2つ目が12346
であれば、12344
の人も12347
の人もいるはずだ、という推測が立つ。
手口2 : セッションIDの盗用
暗号化されていない通信(HTTPS化されていないサイトや、暗号化されていない公衆無線LANでの通信)が傍受されたり、
またXSSなどによってセッションIDが盗まれる危険性がある。
手口3 : セッションIDが固定されていることを利用する
安全なウェブサイトの作り方では「セッションIDの固定化」というタイトルで紹介されているが、個人的には「ウェブアプリケーション側がセッションIDを固定化していることを逆手に取った手口」という言い方の方が理解しやすいと思っているので上記のように言い換えている。
具体的な手口としては下記のようになる。
- 犯人はまず自分でウェブアプリケーションにログインし、自分のセッションIDを得る。
- 何らかの方法(後述)で、第三者(Aさん)に自分のセッションIDを用いてログインするように仕向ける。
- 第三者(Aさん)はそのセッションIDを用いてログインする。
- サーバー側は、「このセッションIDは今ログインしたAさんが送ってきたんだからAさんのものなんだね〜」と認識する。
- セッションIDを知っている犯人は、Aさんになりすますことに成功。
3のログインした時点で新しいセッションIDを発行していればこの攻撃は成立しないが、固定してしまっているために発生する。
何らかの方法とは?
- URLにセッションIDを埋め込んだリンクを踏ませる
- セッションIDがURLのパラメータとして管理されている場合、
http://example.com/login?sessionid=ABC
といったリンクを踏ませることで可能。
- セッションIDがURLのパラメータとして管理されている場合、
- XSS
- セッションIDがCookieで管理されている場合、
<script>document.cookie="sessionid=ABC"; </script>
といったスクリプトを埋め込んでそれを第三者のブラウザで実行させることで可能。
- セッションIDがCookieで管理されている場合、
- HTTPヘッダインジェクション
- 同じくセッションIDがCookieで管理されている場合、Set-Cookieヘッダを挿入することで利用者にCookieを強制することが可能。
※ セッション固定化攻撃については下記のサイトを参考にさせていただいてます。
対策
セッションIDを推測困難なものにする
規則的に生成するのではなく、ランダムに生成されるよう予測できないようにしましょう。
また、フレームワークやライブラリがセッション管理の機能を提供しているのであればそれに則るようにしましょう。
セッションIDをURLパラメータに指定しない
ブラウザのReferer送信機能によってセッションIDがついたURLが送信されてしまうことがある。
セッションIDはCookieかhiddenパラメータに保存しよう。
(hiddenパラメータは書き換え可能なので個人的にはCookieがベターと思う)
なお、phpのsession.use_trans_sid = 1のようにCookieが無効化されている場合自動的にURLパラメータにセッションIDを含める機能もあるが非推奨である。
Cookieにsecure属性を加える
secure属性を加えるとHTTPS通信でしかCookieを利用できなくなる。
HTTP通信だと盗聴の可能性があるので、必ずsecure属性を加えましょう。
また、Ruby on Railsのconfig.force_ssl = true
などのようにSSL通信を強制させ、暗号化されていない無線LANでのアクセスなどを禁止し盗聴対策することができるでのこちらもやっておきましょう。
ログイン成功後に新しいセッションIDを発行しよう
固定化攻撃を防ぐため、ユーザーごとに固定のセッションIDを持つのはやめ、
ログインの度にセッションIDを新規発行し、既存のセッションIDは無効になるようにしましょう。
Cookieに有効期限を設定しましょう
有効期限が長いほど盗まれる可能性は上がります。適切な期間を設定しましょう。
XSS対策
ユーザーからの入力値をサニタイジングするなど、基本的なXSS対策を行いましょう。