なぜ今さら `rel=”noopener”` なのか?――「別タブ遷移」という小さな穴が招く致命的なリスク
フロントエンド開発の現場で、ごく当たり前のように書く ``。新しいタブで外部サイトを開く際に必須のこの属性ですが、実はこれ、何も対策せずに放置していると、あなたのサイトのセキュリティを自らドブに捨てるような行為になりかねません。
「たかがリンク」と侮るなかれ。今日は、なぜ `noopener` と `noreferrer` が必須なのか、そして裏側でブラウザが何をサボり、何を隠そうとしているのか、実務レベルの視点で深掘りしていきます。
—
1. なぜ `target=”_blank”` は危険なのか?
結論から言えば、最大の敵は `window.opener` というプロパティにあります。
`target=”_blank”` で開かれたリンク先のページ(遷移先)は、JavaScriptで `window.opener` を参照することで、遷移元のページ(あなたのサイト)の `window` オブジェクトを操作できてしまうのです。
攻撃のメカニズム
1. ユーザーがあなたのサイトから、攻撃者が用意した悪意あるページへ飛ぶ。
2. 攻撃者のページで `window.opener.location.href = ‘https://phishing-site.com’` のようなスクリプトが動く。
3. ユーザーが見ていたあなたのサイトが、知らないうちにフィッシングサイトに書き換わっている。
ユーザーからすれば「元のサイトに戻ろうとしたら、怪しいサイトに飛ばされた」という現象が起きます。これはUX的にもセキュリティ的にも最悪です。
2. ブラウザの裏側で何が起きているか
現代のブラウザは賢くなりました。かつては全ブラウザで `window.opener` が生きていましたが、現在は多くのブラウザで `target=”_blank”` を指定すると、暗黙的に `rel=”noopener”` が付与される挙動をとるようになっています。
しかし、「ブラウザがやってくれるから大丈夫」という考え方はエンジニアとして最も危険です。
古いブラウザや特定の環境下では挙動が保証されませんし、何よりHTTPリファラーの漏洩問題は別次元の話だからです。
`noopener` と `noreferrer` の使い分け
- `rel=”noopener”`: `window.opener` へのアクセスを遮断し、遷移先から遷移元を操作させない。
- `rel=”noreferrer”`: `noopener` の機能に加え、遷移先に `Referer` ヘッダー(どのページから来たかという情報)を送信しない。
3. 実践:現場で使うべきベストプラクティス
正直なところ、現代のWeb開発において「外部サイトへのリンク」であれば、迷わず両方つけるのが正解です。リファラーを意図的に渡す必要がない限り、情報を削ぎ落とすことは防御の第一歩です。
以下に、そのままプロジェクトに組み込めるクリーンなコード例を示します。
Reactなどのモダンフレームワークを使っている場合
React(JSX)では `rel` 属性を文字列で渡すだけでOKです。コンポーネント化して「外部リンク用リンク」としてラップしておくのが、チーム開発における事故防止の鉄則です。
// 外部サイト遷移用の再利用可能コンポーネント例
const ExternalLink = ({ href, children }) => {
return (
{children}
);
};
—
4. シニアエンジニアからのワンポイントアドバイス
「リファラーが必要な場合があるのでは?」という疑問を持つ方もいるでしょう。例えば、アフィリエイトの計測や、遷移先で特定のトラッキングを行いたい場合です。
その場合は、`rel=”noopener”` のみを付与するか、あるいは `Referrer-Policy` ヘッダーでサイト全体(あるいは特定リンク)のポリシーを制御するのがスマートです。HTMLの属性だけで完結させようとせず、HTTPレベルでのコントロールを検討するのが、中級から上級へステップアップするための視点です。
最後に
セキュリティ対策は「面倒くさい」と感じる瞬間こそが、最も重要です。
今回紹介した `rel=”noopener noreferrer”` は、実装コストが限りなくゼロでありながら、守れる資産は非常に大きい。こういった「些細な積み重ね」を当たり前にこなせるエンジニアこそが、信頼されるプロダクトを作れると私は信じています。
今日のコードをPushする前に、一度だけ、あなたのプロジェクトの全リンクを見渡してみてください。「あ、ここ抜けてた」という箇所が見つかるはずです。それが、あなたの開発スキルが一段上がった証拠です。

コメント