概要
この記事は主に以下の内容に触れていきます!
- Refererというものはそもそもなんなのか
- Refererはどのように動いているのか
- セキュリティを意識したReferrer-Policyを設定するにはどうすればいいのか
- 番外編: target=_blankでの脆弱性
つい半年ほど前にGoogleがChromeのデフォルトのReferrer-Policyを変更して話題になりましたね。
この記事を読んでいただければGoogleがReferrer-Policyを変更した背景も分かってくるかと思います!
参考記事: Entry is not found - paiza開発日誌
Referer is 何?
HTTPリファラ(英: HTTP referer)あるいは単にリファラは、HTTPヘッダの1つで、インターネット上の1つのウェブページまたはリソースから見て、それにリンクしているウェブページやリソースのアドレス[1]を指す。リファラを参照することで、どこからそのページに要求が来たのかを知ることができる。
参照: HTTPリファラ - Wikipedia
つまりRefererとはどのページからアクセスが来たか情報を渡すためのHTTPヘッダの種類の一つであると言えます!
例えばGoogle検索からの流入の場合HTTPのリクエストヘッダにはReferer: https://www.google.com/
の値がつき、この情報を集めることによってユーザーがどのサイトを経由してページにやってきたのか知ることができます。
Web広告を回すマーケターのかたにとっては必須の情報ですね!
HTTPについて詳しく知りたい方はこちらの記事に丁寧にまとめられています↓
HTTPのバージョンについてまとめ
*ちなみにreferer
の綴りが参照元という意味の英単語であるreferrer
と違うのはHTTPが策定された時にヘッダ名を間違えたスペルで書いてしまい、それが今でも使われているという歴史的経緯があるようです...(ちなみに後からから出てくるReferrer-PolicyはスペルミスをしなかったそうでReferrerのままです笑)Referrer-Policy - HTTP | MDN
Refererは誰が送ってるの?
Refererを送っているのはwebブラウザ(chrome, IE, FireFoxなど)です。
ブラウザが自動でRequestヘッダーのrefererに送信元のURL情報を付与しています。
ブラウザによってはReferer送信に対応していないものもあるのでこのサイトでチェックしてみて下さい!(ほとんどのモダンなブラウザでは対応しています)
Can I use... Support tables for HTML5, CSS3, etc
Refererが生じる脆弱性
Refererの情報は流入元を知れるためとても便利な反面、Refererによってもたらされる脆弱性もあります。
それはURLに重要情報が含まれていた場合、その情報が遷移先のサイトに送られてしまうことです。
Refererによって重要情報が漏洩する例
例えば脆弱性の高いサイトhttps://example.com
でユーザー登録をしたとしましょう。
登録ボタンを押すとメールが送信され、そのメールに以下のようなメールアドレスとパスワードが埋め込まれたhttps://example.com/auth?email=hogehoge@gmail.com&password=hugahuga123&token=ndjask819Sjks
というリンクが貼られています。
URLに情報が既に入っていることにより、このリンクをクリックすることでメアドとパスワードを再度入力することなく、認証に成功します。
そしてサイト内の記事に貼ってある外部リンクhttps://insecure.example.com
に遷移したとしましょう。そうするとreferer情報としてReferer: https://example.com/auth?email=hogehoge@gmail.com&password=hugahuga123&token=ndjask819Sjks
がhttps://insecure.example.com
に送られてしまいます。
もしこのサイトの運営者が悪意のある人だった場合、Referer情報から個人情報を取得し、悪用することができてしまします。
どうすればこの脆弱性を回避することができるでしょうか?
URLにセキュアな情報を入れないようにすることは大事ですがUX向上のためどうしても入れたい場合(認証でのリダイレクトログインなど)もあるかと思います。
そんな時に登場するのがReferrer-Policy
です。
Referrer-Policyの役割
Referrer-Policyは以下のようなmetaタグに設定することでrefererを送信するブラウザの挙動を変更することができます。
例:
<meta name="referrer" content="strict-origin-when-cross-origin" />
このcontent
の種類によってreferer送信の挙動をコントロールすることができます。
例えば
-
no-referer
: 全く送らない -
strict-origin-when-cross-origin
: HTTPS間またはHTTP間のリクエストの時origin(サーバーのドメイン名またはIPアドレス)だけ送る、さらに同じoriginでのリクエストの場合は全てのURLを送る
などです!
設定できる値はこちらのサイトに詳しく載っています。
Referrer-Policy - HTTP | MDN
とりあえず一覧でざっくりとみたい!という方のために分かりやすい画像があったので添付しておきます。
画像URL: https://web.dev/referrer-best-practices/
このReferrer-Policyは実はブラウザごとにdefaultの値が決まっています。
画像URL: Referer and Referrer-Policy best practices
*Chromeは2020年8月26日よりdefaultがstrict-origin-when-cross-origin
に変更されました。
Referrer-Policyのベストプラクティス
refererはユーザーの流入元が分かり便利な反面、個人情報などが外部のサイトに知られてしまう脆弱性があるというリスクがあることが分かりました。
それではReferrer-Policy設定のベストプラクティスは何なのでしょうか?
サイトにおける要件により変わってくるかと思いますが、大体のサイトで求められるのが
- 外部サイトには全てのURLを送りたくない
- 同じサイト内での遷移は全てのURLを送りたい(tracking等便利な為)
- HTTPへリクエストを送るときはrefererを送りたくない(中間者攻撃を防ぐため)
の3点です。この条件を満たすのはstrict-origin-when-cross-origin
となるのでメタタグに
<meta name="referrer" content="strict-origin-when-cross-origin" />
を設定しておくことで適切かつ安全なrefererを送信できるようになります!
Chromeはこちらの設定がデフォルトになりましたがFireFoxやEdgeなどはデフォルトがno-referrer-when-downgrade
になっているのでこちらのタグを明記しておくことが大切です!
最新の対応状況はこちらのサイトからご確認ください!
Can I use... Support tables for HTML5, CSS3, etc
番外編~別タブで外部リンクを開く場合(target=_blank)~
Googleのエンジニアが<a>
タグでtarget=_blank
を用いた別タブでの外部サイトを開く際に重大な脆弱性があることを指摘しました。
記事: Links to cross-origin destinations are unsafe
記事によると
target="blank" を使用して任意のページから別のページにリンクしている場合、リンク元のページとリンク先のページは同じプロセスで動作します。 そのため、リンク先のページで負荷の高い JavaScript が実行されていると、リンク元のページのパフォーマンスが低下するおそれがあります。
また、target="blank" にはセキュリティ上の脆弱性もあります。リンク先のページでは window.opener を使用して親ウィンドウのオブジェクトにアクセスしたり、window.opener.location = newURL によって親ページの URL を変更したりできます。
これはどういった脆弱性なのかというとtarget=_blankで開いたサイトではwindow.openerを使用することで親ページのURLを書き換え別のページに遷移させることができるといった脆弱性です。
こちらのサイトでとても分かりやすく(実際にリンクを踏んで挙動を確認することもできます)まとめられていたので、気になる方は確認してみて下さい。
リンクを作る時の target="_blank" の危険性
こちらの脆弱性を防ぐためには
<a href="https://examplepetstore.com" target="_blank" rel="noopener">
Example Pet Store
</a>
のようにrel="noopenner"
を指定することでwindow.opener
プロバティへのアクセスを防ぐことができます。
さらにrefererも送信したくない場合はrel="noreferrer"
を設定することによってwindow.opener
プロバティへのアクセス、refererの送信両方を防ぐことができます。
適切に使い分けて脆弱性とは無縁な安心安全のエンジニアライフを送っていきましょう!