サードパーティオリジンの LocalStorage の挙動を調べてみた
こんにちは。花金だ! きたけーです。
サードパーティオリジンの LocalStorage の挙動をChromeとSafariで調べてみたのでメモ。
やりたいこと
iframeで別オリジンのページを読み込み、元のページからiframeのwindowに値を送ってLocalStorageに値を保存したい。
検証用のコード
- window.postMessageをつかって値を送る
- foo.dev, bar.dev を 127.0.0.1 で名前解決できるようにしておく
- 元のページは http://foo.dev:3000/parent.html, iframeのほうは http://bar.dev:3000/child.html でアクセスする
元のページ
- ロード時に LocalStorage に指定されたキーの値が存在するか調べ、なければ値(日付と乱数)を生成して、LocalStorageに格納、画面に表示する
- ボタンを押すと、iframeで読み込んだページに ↑で生成、格納した値をPostMessageで送る
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>parent</title> <script> var key = "test_item"; var value = ""; window.onload = function () { var resultElm = document.getElementById('result'); value = localStorage.getItem(key); if (!value) { value = [(new Date()).toString(), Math.floor(Math.random() * 10e12)].join('\t'); localStorage.setItem(key, value); } resultElm.innerHTML = value; }; var sendValue = function () { var iframeElm = document.getElementsByTagName('iframe')[0]; iframeElm.contentWindow.postMessage(value, 'http://bar.dev:3000'); }; </script> </head> <body> <div id="result"></div> <iframe src="http://bar.dev:3000/child.html" frameborder="0"></iframe> <button onclick="sendValue()">送る</button> </body> </html>
iframeで読むこむページ
- PostMessageで送られた値をLocalStorageに指定されたキーで格納、画面に表示する
- ロード時に LocalStorage に指定されたキーで格納された値を表示する
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>parent</title> <script> var key = "test_item"; window.onload = function () { var resultElm = document.getElementById('result'); resultElm.innerHTML = localStorage.getItem(key); } window.addEventListener("message", function (event) { var resultElm = document.getElementById('result'); if (event.origin !== "http://foo.dev:3000") { return; } localStorage.setItem(key, event.data); resultElm.innerHTML = event.data; }); </script> </head> <body> <div id="result"></div> </body> </html>
Chromeの場合
バージョンは 38.0.2125.111
表示はこんなかんじ。 PostMessageで値を送ってLocalStorageに保存した後に、「リロード」、「新しくウィンドウやタブを開いてページにアクセスする」、「ブラウザを起動し直す」などをしても、LocalStorageに格納された値は消えないことが分かる。
Safariの場合
バージョンは 7.0.6 (9537.78.2)
これがSafari7以降だと、おもしろい挙動になる。PostMessageで値を送って、LocalStorageに保存する処理が走った後にも関わらず、WebインスペクタでLocalStorageの内容が空っぽになっている。
リロードした場合は、iframeのほうで値を表示されるが、ウィンドウやタブを新しく作成してアクセスすると、iframeのほうでは値が表示されない。
どうやら、Safari7.0以降(また、iOS7 の Safari)では、サードパーティオリジンの WebStorage (LocalStorage, SessionStorage) に対するポリシーが変更されたらしく、LocalStorageはSessionStorageになるらしい。 (refs: webkit ではサードパーティドメインの localStorage が sessionStorage になる - Please Sleep)
じゃあ、SessionStorageに値が格納されているのか、と思って、調べてみたら空っぽだった。「SessionStorageになる」というよりは「格納期間の単位がセッションになる」というほうが正確かもしれない。
ちなみに、この挙動はSafariの「Cookie とその他の Web サイトのデータをブロック」の設定によるものでデフォルトの「知らないサイトや広告のみ」だと↑で説明した挙動、「しない」にすると↑のChromeでの挙動と同じになる。Chromeには「サードパーティの Cookie とサイト データをブロックする」(デフォルト オフ)があり、Chromeのサードパーティオリジンの LocalStorageの挙動もこの設定のオン・オフで変わるかもしれない(ちょっと時間がないので今回はこれまで)。