at backyard

Color my life with the chaos of trouble.

target="_blank"のリンクを踏んだのにwindow.openerにnullが入ることについて

目次

target="_blank"の危険な理由

最近、aタグについて調べる機会があった。

<a href="http://example.com" target="_blank">insecure link</a>

というリンクを作成した際に、リンク元でopenerの情報にアクセスできてしまうという話は普段web系の分野で動かれている方にとっては有名な話だが、では、試しにその手法を試してみようと思って簡単なサンプルを作成した際に、window.opener の中が nullになっていることに気づいた。

※本来上に貼ったinsecure link を踏んだ場合、window.opener に遷移元のページ情報が格納されており、この情報を悪用して遷移先のページで下記のようなJavaScriptを埋め込んでおくことで指定したページに遷移させることが可能になるというものだったかと思う。

window.opener.location = 'http://example.com';

ただし、上にも書いたように window.opener の中身は null になっていた。

“target=_blank”のリンクは“rel=noopener”が付いているものとして扱われることになった

これについては下記のような変更が行われたようだ。

確かにセキュリティ面を考えると、こちらのほうが安全ではある。

forest.watch.impress.co.jp

forest.watch.impress.co.jp

window.open関数を使えばwindow.openerにはアクセスできる

ではもうwindow.openerにはnullしか入らなくなったのだろうか、というとそんなことはなく、window.open 関数を使って遷移を行った場合には注意が必要だ。

例えば下記のようなリンクがある場合、window.openerには情報が入る。

<a href="./index2.html" target='_blank' onclick="window.open(this.href,this.target);return false;">insecure link</a>

onclickイベントの最後に "return false;"を付ける理由

ちなみに少し話がそれるが、上のコードでonclickイベントでの処理の最後に return false;を書いているのはリンクの既定のアクションをキャンセルすることが目的となるらしい。

ここについてはMDNの下記のページが詳しい。

https://developer.mozilla.org/ja/docs/Web/API/Window/open#best_practices

コード内の return false の目的は、リンクの既定のアクションをキャンセルすることです。 onclick イベントハンドラーが実行される場合、リンクの既定のアクションを実行する必要はありません。しかし、ユーザーのブラウザーjavascript サポートが無効、もしくは、存在しない場合、onclick イベントハンドラーは無視され、ブラウーーは、target の "PromoteFirefoxWindowName" という名前のフレーム、もしくは、ウィンドウ内の参照されたリソースを読みこみます。

しかし、いまいち、return false:を書いたときにどう動作が変わってくるのかがまだ理解できていない。
これについては別途時間を見つけて調べて見るかもしれない。

window.openerに情報が入るパターンのリンクについて

window.openerに値が入るリンクを上に書いたが、他にもパターンはあるので、ここではそれを列挙してみようと思う。

まずは上に書いたパターンで、onclickでwindow.openを利用したパターンだ。

ちなみにwindow.open関数は第2引数にaタグでいうtarget属性となる、windowNameが指定できる。

developer.mozilla.org

<a href="./index2.html" target='_blank' onclick="window.open(this.href,this.target);return false;">insecure link</a>

次にwindow.open(url) というパターン。

<a href="./index2.html" onclick="window.open(this.href);return false;">insecure link 2</a>

第2引数に_blankを指定したわけではないのに、遷移後のページでwindow.openerの中に情報が入っている。

次はrel="noopener noreferrer" を指定してもwindow.open関数では特にそれらを指定していない場合。

<a href="./index2.html" target='_blank' rel="noopener noreferrer" onclick="window.open(this.href,this.target);return false;">insecure link 3</a>

ちなみに、return false;の記述を削除しても、この挙動は変わらなかった。

<a href="./index2.html" target='_blank' rel="noopener noreferrer" onclick="window.open(this.href,this.target)">insecure link 3</a>

window.openを使った遷移してもwindow.openerに何も入れないためにはどうすればよいか?

これは上に貼ったMDNのページ内にも書いてあるが、下記のように第3引数に"noopener noreferrer"を記述すれば window.openerはnullとなる。

<a href="./index2.html" target='_blank' onclick="window.open(this.href,this.target, 'noopener noreferrer');return false;">secure link2</a>

というわけで、window.openerについて調べてみた備忘録でした。

target="_blank"の危険な動作を試す

なお、これらのコードはGitHubにあげています。

github.com

人のサーバで危険な動作を試すのは抵抗あると思うので(私は怖い)、GitHubからダウンロードしてローカルでお試しください。

実際の動作としては insecure link を踏むと、踏んだ遷移先のページで下記のようなJavaScriptが動く。

    console.log(window.opener);
    if(window.opener) {
        window.opener.location = "./index3.html";
    }

遷移元のページがリンクをクリックした直後に意図しないページに変わっているのが確認できる。