結論(別タブリンクのnoopener)
別タブリンクのnoopenerとは、target="_blank" で別タブに開くリンクに rel="noopener"(または noreferrer)を付ける対策です。開いた先のページから window.opener で元のページを参照・遷移させないようにします。これにより、外部サイトを見ている間に元の自治体サイトのタブが偽ページへすり替わる「リバースタブナビング」を防げます。現行の主要ブラウザは既定でnoopener動作をしますが、古い環境のために明示が推奨されます。
この記事のポイント
- rel="noopener" を付けると、開いた先から window.opener が null になります。
- noreferrer は noopener の効果を含み、さらにRefererヘッダーを送りません。
- 現在のHTML標準では target="_blank" は暗黙に noopener と同じ動作で、MDNの互換性データではChrome 88・Edge 88・Firefox 79・Safari 12.1から既定です。
- 古いブラウザや更新されていないアプリ内ブラウザには既定動作が適用されないため、明示が推奨されます。
- セキュリティAIチェッカーは、noopener・noreferrerのない target="_blank" のリンクが1件でもあれば△と判定します。
| 診断項目名 | 別タブリンクのnoopener |
|---|---|
| 項目ID | html.noopener |
| 分類 | HTML・JavaScript・外部資産 |
| 重大度・配点の重み | 中(medium) 重み 2 |
| 関連する標準・ガイドライン | OWASP WSTG-CLNT-14「Reverse Tabnabbing」/OWASP HTML5 Security Cheat Sheet(Tabnabbing)/HTML Standard「get an element's noopener」/CWE-1022(window.openerアクセスを伴う信頼できないリンク先の使用)/関連: ASVS 5.0.0 V3.4.8(L3: Cross-Origin-Opener-Policyによるtabnabbing等の防止) |
別タブリンクのnoopenerとは
別タブリンクのnoopenerとは、target="_blank" で別タブ(別ウィンドウ)に開くリンクに rel="noopener"(または noreferrer)を付け、開いた先のページから window.opener を通じて元のページを操作させないようにする対策です。
<a href="https://www.example-vendor.jp/" target="_blank" rel="noopener noreferrer">関連サイト(別ウィンドウで開きます)</a>
target="_blank" で別タブに開いたページは、古い仕様のブラウザでは window.opener を通じて元のページを参照でき、window.opener.location = "https://偽サイト/" のように元のタブを別のページへ遷移させることができました。利用者が別タブで外部サイトを見ている間に、元の自治体サイトのタブが偽のログイン画面や偽の申請ページにすり替わる攻撃を「リバースタブナビング(reverse tabnabbing)」と呼びます。
rel="noopener"(または noreferrer)を付けると、開いた先から window.opener が null になり、この攻撃を防げます。セキュリティAIチェッカーのこの項目は、トップページの target="_blank" リンクに noopener または noreferrer が付いているかを確認します。
target="_blank"とnoopenerの現在の仕様・ブラウザの動作
HTML Standardの「get an element's noopener」
HTML Standardの「get an element's noopener」アルゴリズムは次のように定めています。
- リンク種別に
noopenerまたはnoreferrerが含まれていればnoopenerとする - リンク種別に
openerが含まれず、targetが_blankであれば、noopenerとする
つまり現在の標準では、target="_blank" は明示しなくても rel="noopener" と同じ動作になり、rel="opener" を書いた場合だけ旧来の動作になります。MDNも、a・area・form 要素の target="_blank" は暗黙に rel="noopener" と同じ動作になると説明しています。MDNのブラウザ互換性データでは、この既定動作はChrome 88、Edge 88、Firefox 79、Safari 12.1から導入されています。
それでもnoopenerを明示すべき理由
現行ブラウザの利用者に対する実害は小さくなっています。それでも明示を推奨する理由は次のとおりです。
- 上記より古いブラウザや、更新されていないアプリ内ブラウザでは既定動作が適用されない
- 明示しておけば、ブラウザの実装に依存せず意図がコード上で明確になる
- WSTG-CLNT-14は、
target="_blank"のリンクでnoopener・noreferrerが使われていない場合を確認対象としている
noopenerとnoreferrerの違い
| 値 | window.opener | Refererヘッダー |
|---|---|---|
noopener | null にする | 送信する |
noreferrer | null にする(noopenerと同じ効果を含む) | 送信しない |
HTML Standardでは noreferrer は noopener の効果を含みます。したがって rel="noreferrer" だけでもリバースタブナビング対策としては十分です。参照元を相手に伝えたくない場合(相談窓口ページのURLなど)は noreferrer を併用します。サイト全体のRefererの送り方は「Referrer-Policy」で確認します。
この項目が対象にしないもの
- JavaScriptの
window.open():こちらは第3引数に"noopener,noreferrer"を指定するか、戻り値のopenerをnullにする必要があります(OWASP HTML5 Security Cheat Sheet)。 - 開かれる側として自サイトを守る対策:ASVS 5.0.0 V3.4.8は、HTMLを返す応答に
Cross-Origin-Opener-Policy: same-origin(またはsame-origin-allow-popups)を付けて、tabnabbingなどのWindowオブジェクトの共有を悪用する攻撃を防ぐよう求めています。これは「Cross-Origin-Opener-Policy」の項目で扱います。
別タブリンクのnoopenerの診断基準(セキュリティAIチェッカー)
取得対象
- 入力URLのリダイレクト後の最終URLのHTML本文(最大2MB)を対象にします。
target属性の値が_blank(引用符あり・なし、大文字小文字を問わない)のa要素を数えます。area、form、window.open()は対象外です。
判定ロジック
対象リンクごとに、rel 属性(引用符あり・なしの両方)に noopener または noreferrer のキーワードが含まれるかを確認します。どちらかがあれば保護済みとします。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| 対象外(na) | target="_blank" のリンクが0件 | 採点の分母から除外 |
| ○ 問題なし(pass) | すべての対象リンクに noopener または noreferrer がある | 重み2を満点で加算 |
| △ 要確認(warn) | 1件以上の対象リンクに両方ともない | 重み2×0.45 |
- 根拠欄には「noopener/noreferrerなし: 未設定件数/対象リンク件数」を表示します。
- 現行の主要ブラウザは既定でnoopener動作をするため、×(fail)ではなく△(明示を推奨)とします。
- リンク先が同一サイトか外部サイトかは区別しません。同一サイトのページであっても、そのページ自体が侵害された場合や、さらに外部へ遷移した場合に影響しうるためです。
- 重大度はmedium、重みは2です。
自治体サイトでの判定例
| リンクの記述 | 判定 |
|---|---|
<a href="https://www.example-vendor.jp/" target="_blank" rel="noopener noreferrer"> | 保護済み |
<a href="https://kanko.example.jp/" target="_blank" rel="noreferrer"> | 保護済み(noreferrerはnoopenerを含む) |
<a href=https://example.jp/ target=_blank rel=noopener>(引用符なし) | 保護済み |
関連リンク集に target="_blank" のリンクが20件あり、うち12件に rel の指定がない | △(根拠欄は12/20件) |
<a href="https://example.jp/" target="_blank" rel="nofollow"> | 未設定として数える(noopener・noreferrer のどちらもない) |
| 別タブで開くリンクがない | 対象外 |
別タブリンクにnoopenerがないとどんなリスクがあるか
- フィッシングへのすり替え:利用者がバナーや関連リンクから外部サイトを別タブで開いている間に、外部サイト(または改ざんされた外部サイト)が元のタブを自治体サイトそっくりの偽ページへ遷移させます。利用者は元のタブに戻ったとき、自治体サイトにいると思い込んだまま、偽の電子申請フォームや偽のログイン画面に個人情報を入力してしまう恐れがあります。
- リンク先の侵害を経由した攻撃:自治体サイトは観光協会、地域団体、イベントサイトなど多数の外部サイトへリンクします。リンク先のドメインが失効して第三者に取得されたり、リンク先が改ざんされたりすると、攻撃の起点になります。
- 影響範囲:現行ブラウザでは既定で防がれるため、実際に影響を受けるのは古いブラウザや更新されていない環境の利用者です。ただし行政サイトは幅広い年齢層・端末の住民が利用するため、古い環境の利用者がいることを前提にするのが妥当です。
別タブリンクにnoopenerを付ける方法(HTML・CMS・JavaScript・Next.js・サーバー設定)
1. HTMLへの付与
<a href="https://www.example-vendor.jp/" target="_blank" rel="noopener noreferrer">
関連サイト(別ウィンドウで開きます)
</a>
「別ウィンドウで開きます」の明示は、アクセシビリティ(利用者が予期しない画面遷移を避ける)の観点でも推奨されます。
2. CMSでの一括対応
- CMSのリンク挿入機能やテンプレートで、
target="_blank"を出力する箇所にrel="noopener noreferrer"を付ける設定・改修を行います。WordPressのブロックエディターなど、新しいタブで開く設定時に自動でrelを付けるCMSもあります。 - 既存記事は、データベースや書き出したHTMLを検索して一括置換します。置換前にバックアップを取得してください。
# 未対応リンクの洗い出し(公開ディレクトリ)
grep -rIn -E '<a[^>]*target=["'"'"']?_blank' /var/www/html | grep -v -E 'rel=["'"'"']?[^>]*(noopener|noreferrer)'
3. JavaScriptでの別ウィンドウ
// 推奨: windowFeaturesでnoopenerを指定
window.open("https://www.example-vendor.jp/", "_blank", "noopener,noreferrer");
noopener を指定すると window.open() の戻り値は null になるため、戻り値を使って開いたウィンドウを操作するコードがある場合は見直しが必要です。
4. Next.js(React)
<a href="https://www.example-vendor.jp/" target="_blank" rel="noopener noreferrer">関連サイト</a>
ESLintの react/jsx-no-target-blank ルールを有効にすると、rel のない target="_blank" をビルド前に検出できます。
5. 併用する対策(サーバー設定)
主に自サイトが他サイトから開かれた場合(開かれる側)の保護として、Cross-Origin-Opener-Policyの付与も検討します。same-origin-allow-popups では、自サイトが開いた別オリジンのポップアップとの参照は残るため(MDN)、開く側の対策は rel="noopener" の明示が中心です。
# Apache (.htaccess)
<IfModule mod_headers.c>
Header always set Cross-Origin-Opener-Policy "same-origin-allow-popups"
</IfModule>
# nginx
add_header Cross-Origin-Opener-Policy "same-origin-allow-popups" always;
same-origin は、自サイトが開いたポップアップとの連携(外部の決済画面や認証画面との window.opener 連携など)を壊すことがあります。まず same-origin-allow-popups で影響を確認してください。
6. 確認方法
curl -s https://www.city.example.lg.jp/ | grep -o -i -E '<a[^>]*target=["'"'"']?_blank[^>]*>' | grep -v -i -E 'noopener|noreferrer'
出力がなければ、トップページの別タブリンクはすべて保護されています。ブラウザで別タブを開き、開いた側のコンソールで window.opener が null であることも確認できます。修正後はセキュリティAIチェッカーで再診断し、根拠欄の未設定件数が0になったことを確認してください。
サイトを壊さないための注意点
noreferrerを付けると、リンク先にRefererが送られません。リンク先のアクセス解析で流入元が分からなくなるため、連携先との取り決めがある場合はnoopenerのみにします。- 別ウィンドウで開いたページとの
window.opener連携(旧来の検索窓や地図の選択画面など)を使っている場合は、noopenerで動かなくなります。postMessageを使った連携に置き換えてから付与してください。その際は「postMessageの送受信元を限定」の考え方で、送受信元を固定します。
よくある質問(FAQ)
noopenerとnoreferrerの違いは何ですか?
どちらも開いた先の window.opener を null にします。noopener はRefererヘッダーを送信し、noreferrer は送信しません。HTML Standardでは noreferrer は noopener の効果を含むため、rel="noreferrer" だけでもリバースタブナビング対策として十分です。
現在のブラウザでも rel="noopener" を付ける必要がありますか?
現行の主要ブラウザは target="_blank" を既定で noopener と同じ動作にするため、実害は小さくなっています。それでも古いブラウザや更新されていないアプリ内ブラウザには既定動作が適用されず、明示すれば意図がコード上で明確になるため、付けることを推奨します。
同じサイト内のページへのリンクにも必要ですか?
セキュリティAIチェッカーはリンク先が同一サイトか外部かを区別しません。同一サイトのページでも、そのページ自体が侵害された場合や、さらに外部へ遷移した場合に影響しうるためです。
window.open() で開く場合はどうすればよいですか?
第3引数に "noopener,noreferrer" を指定するか、戻り値の opener を null にします。noopener を指定すると window.open() の戻り値は null になるため、戻り値を使うコードは見直しが必要です。なお window.open() はこの診断の対象外です。
rel="noreferrer" を付けるとアクセス解析に影響しますか?
リンク先にRefererが送られないため、リンク先のアクセス解析で流入元が分からなくなります。連携先との取り決めがある場合は noopener のみにします。
rel="nofollow" だけでは対策になりませんか?
なりません。nofollow は window.opener を null にしないため、診断では noopener・noreferrer のどちらもない未設定のリンクとして数えます。
この項目を含む127項目を、URLを入れるだけで無料診断します。