自分自身をロードするときにフレーム解除してロードしようとするサイトをフレームで開くときの抑制方法

タイトルだけ読んだら意味不明かと思います。要はこういうケースです。

  1. 入力フォームとiframeを用意
  2. 入力フォームがURLだったらiframeに指定されたURLのページを読み込む。要するに簡易ブラウザみたいなの。
  3. ここで入力されたURL先のページが自分自身のwindow.selfを確認してwindow.topに描画されていないと分かるや否や、window.topに再描画する。
  4. すると、iframeを表示していた元の親フレームは上書きされて子フレームに乗っ取られる。

たとえばadidasのサイトなんてそういう挙動をします。分かりやすく具体例を示すためにこんなページを用意しました。Googleボタンを押すとiframeの中身がGoogleに入れ替わり、adidasボタンを押すとadidasのサイトに入れ替わります。adidasボタンを押すと親フレームを乗っ取られることが確認できます。ちなみに、一度乗っ取られるとiframeにadidasのキャッシュが残り、「戻る」でテストページに戻っても強制的にフレーム解除でadidasページに再び飛んでしまうこともあるので、ご注意ください。

これ、どういう仕掛けになっているのか調べてみるとadidasのトップページにこんなスクリプトが入っていました。

if (window.self != window.top) window.top.location = window.self.location;

単純だけど強力なスクリプトです。要するに自身の表示フレームを確認して、window.topに強制描画させています。上記のようにフレーム内呼び出しが(なんらかの方法で)行われた場合、結果的には親フレームは壊されてしまい、完全に乗っ取られる形になります。

unloadをフック

最初はwindow.topを上書きしてアクセス不可にすればいい?と考えてみました。が、子フレームから見たwindow.topを書き換えないとそもそも意味が無いので、子フレームの内容はクロスドメインである場合、その内容にアクセスができないのでこの方法は不可能です。

と、なるとwindow.unloadイベントをフックして、想定外のunloadイベントが起きた場合に限り、window.confirmを出してその場に留まらせればOK?と思い、こんなコードを書いてみました。

$(window).unload(function(){
 window.conform("ページが消される!");
});

でも、これじゃダメ。 イベントはフックできても、confirmの内容に関わらずフレームが乗っ取られます。最後にreturn false;とかしても無駄。

beforeunloadをフック

さらに調べてて辿り着いたのがbeforeunloadイベント。Google Docsなんかで文書が保存されていないときにページから立ち去ろうとするときなんかにconfirmが実行されますが、それはこのbeforeunloadイベントをフックしてるみたい。ちなみにこれはunloadよりも先に発生するイベントのようですね。

で、このbeforeunloadイベント、少し変わった仕様になっていてハンドラに渡ってくるイベントオブジェクトのreturnValueに文字列を指定することで、ページ遷移直前にユーザーに確認ダイアログを表示することができます。あくまでもダイアログを表示するだけで、その結果を拾ったり、結果をもとに新しい処理を行うことは不可能です。(もしそんなことができると永久に閉じれないブラクラを作ることができるので、その対応なんでしょうね)

具体的にはこんなコードで確認ダイアログを表示することができます。

window.onbeforeunload = function(event){
  event = event || window.event; 
  return event.returnValue = '移動しようとしてるよ!';
}

で、これを実際に先ほどのテストページに反映させてみました。

ポイントは2点。まず、最後にreturn文として実行しないとSafari3.2ではダイアログが表示されません。つまり、単純に「event.returnValue = '移動しようとしてるよ!';」だけではダメで、return文にしておくのが重要。

あと、Operaの場合はonbeforeunloadが実装されていません。なので、Operaの場合は残念ながら代用としてunload時にalertを出して「立ち去ります!(ごめん)」と謝るしか無さそうです。(confirmで確認画面を出しても、結果で分岐させることができないのでalertを出すくらいしかできない)

この2点に注意すれば、確認ダイアログでページの移動を許可しない場合において、これまでの例のようなフレーム乗っ取りを抑制でき、ちゃんとフレームの中でadidasのサイトを表示することができます。(IE7, Fx3.0.4, Safari3.2.1, Chrome0.4.1で確認)

まとめ

今回はたまたまadidasさんのサイトを例に出しましたが、このようにフレーム解除して表示しているサイトは実は結構あります。比較的まっとうな使い方の中では(今回の例がまっとうかどうかはさておき)、このようなフレーム解除をされると大変です。そんなとき、スマートな解決策とは言えませんが、今回の方法は1つの解として頭に入れておいていいのかな、と思います。あとはOperaがbeforeunload対応してくれればもっといいのですが。。

あと、onbeforeunloadをjQueryでうまく扱う方法が正直よくわからなかったです。いろんなBlogで出てるようにbindメソッドでハンドリングさせる方法もクロスブラウザでうまくハンドリングできなかったり。「これだとクロスブラウザで大丈夫!」な書き方があれば是非教えていただきたいです。

関連広告

Trackbacks:0

TrackBack URL for this entry
http://blog.katsuma.tv/mt-tb.cgi/181
Listed below are links to weblogs that reference
自分自身をロードするときにフレーム解除してロードしようとするサイトをフレームで開くときの抑制方法 from blog.katsuma.tv

Home > Javascript > 自分自身をロードするときにフレーム解除してロードしようとするサイトをフレームで開くときの抑制方法

Search
Feeds

Return to page top