WebサイトのRefererとは?CSRとSSRでの挙動の違いと対処法
こんにちは、フロントエンドエンジニアのてりーです。
React + TypeScriptを5年以上使い続け、派遣 → フリーランス → メガベンチャーとキャリアを積んできました。
詳しいキャリアや学習ロードマップについてはこちらからどうぞ!
はじめに
Webアプリケーションを開発する中で、一度は耳にしたことがあるHTTPリクエストヘッダーの一つがReferer(リファラー)です。
このヘッダーは、リクエストが送信された際に「どのページからそのリクエストが発生したか」を示す情報を提供します。
しかし、SSR(サーバーサイドレンダリング)からCSR(クライアントサイドレンダリング)に切り替えた際に、このRefererの挙動が変わり、意図しない動作に遭遇することがあります。
本記事では、Refererの仕組みやその役割、SSRとCSRでの挙動の違い、そして問題に対処する方法について解説します。
Refererとは?
Refererの役割
Referer
はHTTPリクエストヘッダーの一つで、現在のリクエストがどのページから発生したかをサーバーに伝える役割を持っています。以下のようなシナリオで使用されます。
- アクセス解析やログ記録
- 外部リンクのクリック元を特定
- セキュリティ(CSRFトークンの検証など)
例えば、ユーザーがページAからページBに遷移した場合、ページBのサーバーに送信されるリクエストヘッダーには、ページAのURLがRefererとして含まれます。
Refererの仕様
Refererはブラウザの挙動や設定、そしてページのプロトコル(HTTP/HTTPS)やCSP(Content Security Policy)によって影響を受ける可能性があります。
- セキュリティ向上のため、HTTPSページからHTTPページへのリクエストではRefererが省略されることがあります
- 同一オリジン間でのみ送信される設定も可能です
参考記事
SSRとCSRでのReferer挙動の違い
SSRでのReferer
SSRでは、リクエストがサーバー上で生成されるため、サーバーが直接遷移前のページのURL(Referer)を取得できます。
ユーザーがページAからページBに遷移した場合、サーバーはページAのURLを正確に把握し、それをRefererヘッダーとしてリクエストに含めることが可能です。
CSRでのReferer
CSRでは、クライアントサイド(ブラウザ上)でレンダリングが行われます。
そのため、リクエストはJavaScriptを介して行われることが多く、この場合のRefererはリクエストを送信した時点の現在のページURLとなります。
つまり、遷移前のページURLをRefererとして取得できません。
以下のような現象が発生することがあります
- SSRでは問題なかったRefererが、CSRでは現在のページURLに変わる
- 明示的にリクエストパラメータにRefererを含めても、ブラウザが自動的に現在のページURLに書き換えてしまう
参考記事
なぜRefererが書き換わるのか?
Refererが書き換わる理由は、ブラウザのセキュリティポリシーに起因します。
セキュリティの観点
- ブラウザは、ユーザーのプライバシー保護のためにRefererヘッダーを適宜変更することがあります
- HTTPSからHTTPへの遷移や、クロスオリジンのリクエストでは、Refererが削除または短縮されることがあります
JavaScriptによる制御の限界
document.referrer
を利用して遷移前のページURLを取得しようとした場合でも、ブラウザによって制限が加えられる場合があります。
このため、アプリケーション側で独自の方法を取る必要があります。
参考記事
CSRにおけるReferer問題の対処法
カスタムヘッダーの使用
CSR環境で正確な遷移前のページURLを取得するために、カスタムヘッダーを利用する方法があります。例えば、x-custom-referer
というヘッダーを定義して、遷移前のページURLを明示的に送信する方法です。
カスタムヘッダーとは?
カスタムヘッダーは、開発者がアプリケーション固有の情報をHTTPリクエストに追加するための手段です。x-で始まる名前を付けることで、標準のHTTPヘッダーと区別します。
実装例
- フロントエンドで遷移前のページを取得
const previousPage = document.referrer;
fetch('/api/some-endpoint', {
method: 'POST',
headers: {
'x-custom-referer': previousPage,
'Content-Type': 'application/json'
},
body: JSON.stringify({ data: 'someData' })
});
- サーバーでカスタムヘッダーを処理
app.post('/api/some-endpoint', (req, res) => {
const customReferer = req.headers['x-custom-referer'];
console.log('Custom Referer:', customReferer);
res.status(200).send('Success');
});
カスタムヘッダーのやり取りに必要なCORS設定についてはこちらの記事にまとまっています!
他の対策
- セッションストレージやローカルストレージを使用して遷移前のページURLを保存する
- ページ遷移時にsessionStorageにURLを格納し、次のリクエスト時に取得して送信する方法
- リクエストパラメータでURLを明示的に渡す
- ページ遷移時にクエリパラメータとして遷移前のページURLを付与する方法
- ただし、URLに直接情報が記載されるため、セキュリティ面での考慮が必要です
実装時の注意点
- Refererヘッダーの取り扱いには十分注意すること
- 不要な情報が漏洩しないよう、HTTPS通信やCSPの設定を活用する
- ブラウザ依存の挙動に注意する。
- Chrome、Firefox、SafariなどのブラウザによってRefererの扱いが異なる場合があります
- パフォーマンスへの影響を考慮する
- カスタムヘッダーを追加する際は、リクエスト全体のサイズや負荷を考慮する必要があります
まとめ
Referer
はWeb開発において便利な情報を提供しますが、SSRとCSRでは挙動が異なるため、実装時には注意が必要です。
特に、CSR環境で遷移前のページURLを取得するには、カスタムヘッダーの利用やセッションストレージの活用などの工夫が必要です。
今後の開発では、Refererの仕様やブラウザのセキュリティポリシーを理解し、アプリケーションの要件に応じた設計を心がけましょう。
Discussion