CookieのPath属性は本当に安全性に寄与しないのか

# [追記] 今度こそ結論。Cookieこそ盗めなくなるが、Ajaxでなんとでもできるので寄与しない

なんと著者から反応がありました。それによると、別のパスからでもXHRやFetchで自由に操作できてしまうので、Cookieを盗むまでもなく被害者の権限で攻撃ができる、ので安全性には寄与しない、とのことです。

確かによく考えるとその通りです。Cookieを盗めるか盗めないか、という点ばかりに目を取られていました。

詳しくはこちらから。

https://qiita.com/ockeghem/items/6590b2e18af1d062e780


以下未修正ですのでご注意ください。

---

先日[体系的に学ぶ 安全なWebアプリケーションの作り方](https://www.sbcr.jp/product/4797393163/)を読んでいて、疑問をいだきました。

4.8.2 クッキーのセキュア属性不備の項で、CookieのPath属性について、

> Path属性を指定しても、安全性が高まるわけではないことに注意してください。その理由は、JavaScriptの同一オリジンポリシーがホスト名単位であり、ディレクトリ単位ではないからです。

と書かれていたのですが、Path属性の指定が安全性に寄与しないのはなぜか、ということについて詳しい説明がありません。同一オリジンポリシーとなんの関係があるのでしょう？

気になったので調べてみました。


# 結論。Path属性は特殊な状況下ではある程度安全性に寄与する

Path属性は、これを設定してCookieを発行するあるパス(以下「自身のパス」)にサーバサイドのプログラムを書き換えられるような脆弱性がなく、同一オリジン内の別のパスにそのような脆弱性がある場合に、そのパスへのCookieの漏洩することを防ぐことができます。

ただし、HttpOnly属性か、HTTPヘッダに`X-Frame-Option: DENY`が設定されている場合に限ります。そうでない場合はXSSによって漏洩します。


# そもそもPath属性はどのように安全性に寄与しそうか？

Cookieは発行時に設定されたドメインにのみ送信されます。Path属性があると、さらに設定されたパスにのみ送信されるよう、追加で制限されます。

例として、あるパス(`/cart/`)以下にログインフォームがあり、ログイン時にセッションIDをCookieで発行する場合、Path属性を`/cart/`に設定しておけば、別のパス、たとえば`/items/`以下からはこのCookieを参照できなくなると考えられます。


# 本当にそんな単純な話なのか？

単純に上記の通りに働くのであれば、「体系的に学ぶ 安全なWebアプリケーションの作り方」に、あのようには書かれていないのではないかと思います。

そのため、なんらかの落とし穴がないか調査しました。その結果、以下の2つの情報源に、Path属性が安全性に寄与しないという情報が見つかりました。


## frame要素を使うと、Path属性を設定したCookieでも別のパスからJavaScriptでアクセスできる

以下のページに詳しい情報があります。frame要素でCookieを盗みたいパスを読み込むことで、`parent.(frame名).document.cookie`経由でPath属性が設定されているCookieをほかのパスから盗み出すことができます。

[高木浩光＠自宅の日記 - 共用SSLサーバの危険性が理解されていない](http://takagi-hiromitsu.jp/diary/20100501.html#p01)
via [CookieのDomain属性は *指定しない* が一番安全 | 徳丸浩の日記](https://blog.tokumaru.org/2011/10/cookiedomain.html)

Chrome, Firefoxのそれぞれ最新版で実験しましたが、現在のブラウザでも動作するようです。同一オリジンポリシーのことを考えれば、この挙動はおそらく仕様なのでしょう。

また、「体系的に学ぶ 安全なWebアプリケーションの作り方」中で"その理由は、JavaScriptの同一オリジンポリシーがホスト名単位であり、ディレクトリ単位ではないからです。"とあった個所は、この仕様について指しているのではないかと思われます。

ただしこの仕様については、HttpOnly属性で回避できます。最近であれば、HTTPレスポンスヘッダに`X-Frame-Option: DENY`(当然、`SAMEORIGIN`では駄目)を設定することでも回避できます。

そのためPath属性を設定していても別のパスにXSSがあればCookieの漏洩を回避できないからPath属性は安全性に寄与しない、とは言えないでしょう。


## Cookieの仕様であるRFC 6265が`セキュリティは Path 属性に依存できない`と言っている

RFCで書かれているのであれば、考慮しないわけにはいきません。以下のページには、

> 所与のホストの中で，パスが異なるクッキーを互いに隔離することは、一見 有用であるが，セキュリティは Path 属性に依存できない（ § セキュリティの考慮点を見よ）。

とあります。

[Cookies: HTTP State Management Mechanism （日本語訳）](https://triple-underscore.github.io/http-cookie-ja.html#sane-path)

「セキュリティの考慮点」の方を見てみますと、Path属性を使っても、およそ以下の2点については安全ではない、とのことのようです。

### 「8.5. 機密性の弱点」より

> クッキーはパスによる隔離を常に供するものではない。 ネットワークレベルのプロトコルでは、あるパスに対応して格納されたクッキーが，別のパスに向けて送信されることはないが、一部の UA は， HTML の document.cookie API などの “非 HTTP” API を介して，クッキーを公開する。

<https://triple-underscore.github.io/http-cookie-ja.html#weak-confidentiality>

こちらは上記の、frame要素を使ってJavaScriptからアクセスする方法も含む問題と考えられそうです。つまり、同じようにHttpOnly属性で別途回避できる問題です。


### 「8.6. 完全性の弱点」より

> Set-Cookie ヘッダが Path 属性をサポートしていても， UA は Set-Cookie ヘッダ内の任意の Path 属性を受容するので、 Path 属性は，いかなる完全性の保護も供さない。 例えば， http://example.com/foo/bar に向けた要請に対する HTTP 応答は、 Path 属性 "/qux" のクッキーを設定できる。 

<https://triple-underscore.github.io/http-cookie-ja.html#weak-integrity>

こちらはCookieの発行時の話であって、セッション固定攻撃には確かにつながります。そしてPath属性ではそれを軽減できないという話で、Path属性によって漏洩を防げるかどうかについては無関係です。


ということで、"セキュリティは Path 属性に依存できない"というのは、Path属性が安全性に寄与しないという話ではなく、Path属性だけでは対応できないセキュリティの問題もある、という程度と考えてよさそうです。


# 結論

ここまでの調査から、以下のことがわかりました。

1. Path属性による制限は、JavaScriptからは回避されてしまう。
2. Path属性による制限は、セッション固定攻撃を防ぐことはできない。
3. それ以外の場合にはPath属性による制限は有効。

3の「それ以外の場合」には、別のパスのサーバサイドのプログラムが攻撃を受けるなどして、そちらからCookieを盗み出せるような場合が含まれます。つまり、Path属性はそのような攻撃を防げると考えられそうです。

具体的にはどのような場合で有効でしょうか？　以下の2つのケースが考えられます。

1. 別のパスだけ、サーバサイドのプログラムが書き換えられる脆弱性がある。
2. 昔あったような、同一オリジン内で、複数の利用者がそれぞれのパスを所有している。

1については、そのようなことを考慮してPath属性による制限をつけるのは、コスト対費用的にあまり意味がなさそうです。

2については、Cookieの漏洩を考慮しなくても危険だらけのため、そのような状況で重要なアプリケーションを動かさないことがまず重要でしょう。

ということで、Path属性は安全性に寄与しないわけではないが、とはいえ考慮すべきほど意味があるとも考えられない、という結論に達しました。

つまり、「体系的に学ぶ 安全なWebアプリケーションの作り方」の記述はおそらく間違えです。

とはいえ私はセキュリティは専門ではなく、特に攻撃側には疎く、この記事に書いた以上の調査・実験もしていないため、この結論も確実とは言い切れません。詳しい情報をお持ちの方がいたら、ぜひご教示ください。


# この記事のライセンス

![クリエイティブ・コモンズ・ライセンス](https://i.creativecommons.org/l/by/4.0/88x31.png)
この文書は[CC BY(クリエイティブ・コモンズ表示4.0国際ライセンス)](http://creativecommons.org/licenses/by/4.0/)で公開します。