これでセキュリティ問題は解決です。めでたし。
* *
* + うそです
n ∧_∧ n
+ (ヨ(* ´∀`)E)
Y Y *
全然めでたしじゃなかった。
思いっきり嘘書いてしまったのでもう少し調べてみます。
bの攻撃
<iframe src="/a/list.php" name="iframeid" id="iframeid" onLoad="hoge();"></iframe>
<a href="#" id="href" onClick="document.body.appendChild(document.createTextNode(iframeid.document.cookie));return false;">Get cookie</a>
<script>
function hoge(){
// /b/上にいるが/a/のCookieが取得できる
document.body.appendChild(document.createTextNode(iframeid.document.cookie));
document.getElementById("href").click();
// 本文も取れる
console.log(document.getElementById('iframeid').contentWindow.document.body);
}
</script>
リンク先のサイトでは手動でクリックさせていましたが、実際はクリックすら不要で、間違って画面を読み込んでしまうだけで/a/のCookieを取得することが可能です。
aの抵抗
a側には対抗策があり、/a/list.phpに
header('X-FRAME-OPTIONS: DENY');
と書いておけばフレームでのファイル読み込みを防ぐことができます。
b側にはBlocked a frameのSecurityErrorが返され、その場合bはaのCookieを読むことはできません。
aもFRAMEを使えなくなりますが、まあ今時フレームなんか使わないから問題ないでしょう。
$.ajax()等では問題なく取得可能です。
b側からフレームでのアクセスはできなくなりましたが、もちろん$.ajax()で本文を取得することは可能です。
しかし、うっかりCookieを画面上に表示していたなどという事故でもないかぎり、aのCookieは取得できません。
bの反撃
b側もこれに対応して、src="/a/image.png"
とかsrc="/a/notexist.php"
とか指定してきます。
画像などのX-FRAME-OPTIONSを仕込めないファイルはPHPでは対抗できません。
また存在しないファイルを指定した場合は404 Not Foundのエラーが返りますが、その場合は何故かaのCookieが読めてしまいます。
aの絶対防御
これに対抗するには、a側は.htaccessで
Header always append X-Frame-Options DENY
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*$ /a/notfound.html [L]
などとしないといけません。
これによって、あらゆるファイルに常にDENYのX-Frame-Optionsがつきます。
また存在しないファイルへのアクセスはエラーページを出すことで、こちらも404 Not FoundではなくSecurityErrorを返すことができます。
逆に言うと.htaccessが設置できないサーバ、設置できてもRewriteEngineが使用できないサーバでは対抗する術がありません。
bのさらなる攻撃
とりあえずこの状態で、私が調べた限りでは/b/以下から/a/のCookieを読み取ることはできませんでした。
が、逆に考えればよいのだ。
読めなければ書き込めばいいと。
setcookie('PHPSESSID', 'evil', time()+999999, '/a/');
同一ドメインなので何の抵抗もなくCookieをセット可能です。
あとは/b/set.phpにアクセスした人がaにログインした頃合いを見計らってアクセスすれば、個人情報を取り出せるという寸法です。
まあ、これはセッション固定攻撃そのものなので、きちんとsession_regenerate_id(true)していれば特に問題ないですが。
まとめ
設定次第では、別ディレクトリからのCookie読み取りを防ぐことは可能のように見える。
何か見逃しているだけだとは思うけど。
書き込みは防げないため、勝手にログアウトされてしまったりという悪戯は可能。
とはいえ、小手先の対策を弄するより、サブドメ切ってくれるサーバに引っ越すのが一番いい。