JavaScript と iframe で注意点

メインのHTML(親frame)の中に子のiframeをつくるとき、その2つのframeの操作について

ぶっちゃけ、そんな都合のいい話はない、というお話。

SameOriginPolicy (同一ドメインポリシー)

  • 操作しようとする2つのwindowやframeのoriginが違う時のポリシー。
  • originは、プロトコルxホストxポート の組合せ。

http://sugilog.hatenablog.com/ と、 http://sugilogtest.hatenablog.com/ はoriginが異なる。 http://sugilog.hatenablog.com/ と、 http://hatenablog.com/ はoriginが異なる。 http://sugilog.hatenablog.com/ と、 https://hatenablog.com/ はoriginが異なる。 http://sugilog.hatenablog.com/ と、 http://hatenablog.com:81/ はoriginが異なる。

  • SameOriginPolicyに反するときは、以下のような操作ができない。
    • 親frameから、iframeのDOMを操作する。またはその逆。
var iframe = parentFrame.frames[0]
iframe.document; // この時点でエラー
iframe.document.getElementById("hoge"); 上でエラーしてるので、こんなことはできるわけもない。
  • 親frameから、iframeの何かしらの情報をみる。またはその逆。
var iframe = parentFrame.frames[0]
iframe.location; // この時点ではエラーしない。
iframe.location.href;; // この時点でエラー。
  • 他、cookieの書き込みとか、ajax関連のこととか、いろいろ。今回はiframeに絞るため割愛。

  • 組合せに対する対処

    • ホスト、ポートが同一で、プロトコルのみが違う場合は、ちゃんと合わせる。(基本)
    • プロトコル、ホストが同一で、ポートのみが違う場合は、なんでわざわざポートを変えるかを再検討。(ケースとしては少ない)
    • プロトコル、ポートが同一で、ホストが全く違う場合は、諦める。
  • サブドメインレベルの違いに対する対応方法

nonsecure content

  • SameOriginPolicy がどうしても切り抜けられないとしたら、iframeとその中身を自前でつくる、という方法も取れる。
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
iframe.contentWindow.document.open();
iframe.contentWindow.document.write("<html><head></head><body>TEST</body></html>");
iframe.contentWindow.document.close();
  • ただし、それをやると、IEに怒られる。(SSLのページの時)

    This page contains both secure and nonsecure items

  • なぜか

    • src要素がないから。
    • モダンブラウザだと(これは仕様か?)でないが、IE6,7,8だとでる。
    • インターネットオプションを変えればでなくもなるが、それはユーザーの対応の話。
  • 副作用もある。

    • document.open()は基本的に危険であること。
    • まちがえて、参照するwindowが、親frameのwindowになっていた場合、ページ全体が真っ白になる。

じゃあどうするのか?

  • iframeを使わないことを考える。 => <script>で必要なデータを読み込む。
    • SameOriginPolicyあたりの話は、frameやwindowの話で、<script>は対象外。
    • JSONPとかの話になっていく。

そもそも論過ぎるが、ブラウザのポリシーの話に立ち入ることになるので、そもそも論で考え直す。

さいごに

というか、2つのドメイン使うことないし、とか、そういうのは、流してください。 自分の中でもレアケースです。