はじめに
外部リンクを target="_blank" で別タブに開く実装はよく使われるが、セキュリティ上のリスクがあります。
この記事では、リスクの仕組みと正しい対策方法をまとめます。
タブナビング攻撃とは
攻撃の仕組み
target="_blank" で開かれた新しいタブは、デフォルトで元のページへの参照(window.opener)を持つ。
攻撃者はこの参照を利用して、元のページのURLを書き換えることができる。
// 悪意のあるサイト側のコード例
if (window.opener) {
window.opener.location = "https://fake-login.example.com";
}
攻撃の流れ
- ユーザーが正規サイトで外部リンクをクリック
- 新しいタブで外部サイトが開く
- 外部サイトが
window.opener.locationを使い、元のタブを偽のログインページにリダイレクト - ユーザーが元のタブに戻ると、偽のログインページが表示されている
- 「セッションが切れた」と思い込み、IDとパスワードを入力してしまう
ユーザーから見ると元のタブのURLが変わっただけなので、攻撃に気づきにくいのが特徴。
対策に使う属性
rel="noopener"
window.opener への参照を null にし、新しいタブから元のページを操作できなくする。
<a href="https://example.com" target="_blank" rel="noopener">リンク</a>
rel="noreferrer"
リファラー情報(どのページからアクセスしてきたか)を送信しない。noopener の効果も含む。
<a href="https://example.com" target="_blank" rel="noreferrer">リンク</a>
リファラー(Referrer)とは
HTTPリクエストヘッダーに含まれる、遷移元ページのURL情報。
アクセス解析に利用されるが、プライバシー保護の観点から送信しないことが望ましい場合がある。
noreferrerを指定すると、リンク先にこの情報が渡らなくなる。
両方指定する理由
| 属性 | セキュリティ(opener無効化) | プライバシー(リファラー非送信) |
|---|---|---|
noopener |
対応 | 非対応 |
noreferrer |
対応 | 対応 |
| 両方指定 | 対応 | 対応 |
noreferrer だけでも noopener の効果を含むが、両方指定することで意図が明確になり、ブラウザ間の挙動差も吸収できる。
正しい実装
基本形
<a href="https://example.com" target="_blank" rel="noopener noreferrer">外部リンク</a>
JavaScriptで動的にリンクを開く場合
window.open を使う場合も noopener を指定する。
// ✅ noopenerを指定
window.open("https://example.com", "_blank", "noopener,noreferrer");
// ❌ 指定なし(window.openerが渡ってしまう)
window.open("https://example.com", "_blank");
Reactでの実装例
// 外部リンク用コンポーネント
const ExternalLink = ({ href, children }) => (
<a href={href} target="_blank" rel="noopener noreferrer">
{children}
</a>
);
ESLintによる自動チェック
eslint-plugin-react を使えば、rel 属性の付け忘れを自動で検出できる。
{
"rules": {
"react/jsx-no-target-blank": "error"
}
}
ブラウザの対応状況
2021年以降のモダンブラウザでは、target="_blank" を指定すると自動的に noopener が適用されるようになっている。
| ブラウザ | 自動 noopener 対応バージョン |
|---|---|
| Chrome | 88+ |
| Firefox | 79+ |
| Safari | 12.2+ |
| Edge | 88+(Chromium版) |
明示的に指定すべき理由
- 古いブラウザ(IE、旧Edge)では自動適用されない
-
noreferrerは自動適用の対象外のため、プライバシー保護には明示的な指定が必要 - コードレビュー時にセキュリティ対策の意図が伝わりやすい
対策が不要なケース
すべてのリンクに一律で付ける必要はない。以下のケースでは対策は不要。
-
同一サイト内のリンク
同じオリジンであればwindow.openerを悪用されるリスクはない -
target="_blank"を使わないリンク
同一タブで遷移する場合はwindow.openerが発生しない
オリジン(Origin)は、URLの「スキーム(プロトコル)」「ホスト(ドメイン)」「ポート番号」の3つの組み合わせのこと
まとめ
-
target="_blank"にはrel="noopener noreferrer"を必ず追加する -
window.openで動的に開く場合もnoopenerを忘れない - モダンブラウザでは
noopenerが自動適用されるが、明示的な指定が推奨 - ESLintなどのツールで付け忘れを防止する
参考サイト