かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

HTML 本当は怖い target="_blank" 。rel="noopener" ってなに?

WordPressの投稿で別ウィンドウで開くリンクtarget="_blank"を作成すると、

<a href="{URL}" target="_blank" rel="noopener">LINK TEXT</a>

のようなrel="noopener"属性を持ったaタグが出力されます。

rel="noopener" の意味

1. target="_blank" のセキュリティ上の脆弱性の問題を避ける

Without this, the new page can access your window object via window.opener. Thankfully the origin security model of the web prevents it reading your page, but no-thankfully some legacy APIs mean it can navigate your page to a different URL using window.opener.location = newURL.
出典: The performance benefits of rel=noopener - JakeArchibald.com

target="_blank"で開かれたページは、元のページをwindow.openerオブジェクトとして持つので、リンク先のページからwindow.opener.location = "danger site url" のように元ページを操作することが出来てしまうようです。

rel="noopener" を使うことで、新しく開いたページからwindow.openerオブジェクトを使って元ページの操作をできなくできるようです。no・openerですね。

DEMO
noopener DEMO

noopener demo page | github.io

rel="noopener"のないリンク先から元ページを操作しているのが解るかと思います。

2. パフォーマンス低下の問題を避ける

This means JavaScript running on one domain runs on a different thread to a window/tab running another domain.
However, due to the synchronous cross-window access the DOM gives us via window.opener, windows launched via target="_blank" end up in the same process & thread. The same is true for iframes and windows opened via window.open.

出典: The performance benefits of rel=noopener - JakeArchibald.com

target="_blank"で開かれたページは、元ページとJavaScriptが同じプロセス・スレッドで動作するようです。
なので、target="_blank"で開かれたページに負荷の高いJavaScriptが実行されていると、元ページのパフォーマンス低下など影響がある可能性があるようです。

Google的見解

監査に合格する方法
レポートを確認して、Lighthouse で特定された各リンクに rel="noopener" を追加します。 一般的に、外部リンクを新しいウィンドウまたはタブで開く場合は、必ず rel="noopener" を追加してください。
出典: Links to cross-origin destinations are unsafe

Goolge的には基本的にtarget="_blank"を使用したリンクにはrel="noopener"をつけたほうが良さそうな雰囲気っぽいです。
 

JavaScriptから元ページを操作できるのってJavaScriptwindow.open()した時だと思っていました。
まさかHTMLのリンクタグのtarget="_blank"からも操作できるとは思ってなかったです… そして、target="_blank"で開かれたページが元ページと同じプロセスになるってのは、開かれたページからwindow.openerが使えるって部分からなんとなく納得。
というか同じプロセスになる仕様だからwindow.openerが使えちゃうってって感じでしょうか?

それよりtarget="_blank"で新しく開いたページからwondow.openerで元ページを操作できるってのが衝撃的だったので、新しく開くリンクにはrel="noopener"積極的につけていこうと思いました。

追記 rel="noopener" のサポート状況

I can useでみてみると… 2018年1月末の状態で、
rel="noopener" 対応状況 Can I use... Support tables for HTML5, CSS3, etc

IEはまぁうん。しかしEdge… お前もダメなのか…
という状況のようです。


[参考]

おまけ rel 属性 のメモ
意味
nofollow 重要でないリンク・リンク先のリンクをクロールしない
信頼できないコンテンツ・ユーザー投稿に含まれるリンクなどに指定
noreferrer リンク先にリファラを送信しない
noopener リンク先のページでwindow.openerによる元ページの操作を禁止する
alternate 代替ドキュメントへのリンク
author 著者へのリンク
license ライセンス文章へのリンク
help ヘルプへのリンク
bookmark このページをブックマークできる固定リンク
prev 前のページへのリンク
next 次のページへのリンク
prefetch リンク先を予めキャッシュする
tag このページのタグ
search 検索機能
icon アイコン・ファビコンとか e.g. <link rel="icon" href="/favicon.ico">
stylesheet CSSの読み込み ※ linkタグのみで使用可

昔のWordPresstarget="_blank"のリンクに出力されるのrel="noreferrer"だったような気がしてたのですが、
WordPress v4.7.4 以降では rel="noreferrer noopener"で、
WordPress v4.8 から rel="noopener" だけになったみたいです。
テーマ作ってばかりで管理画面からの投稿はほぼ使ってないので気づいてませんでした…
(定期的にソース開く癖つけないとダメですね)

[参考]