ある日、ページの開発中に、リクエストヘッダのフィールドが正しいかどうかをチェックするために、開発ツールを開いてみると、いくつかの怪しいヘッダが追加されていることに気付きました:
怪しい箇所に気づきましたか?よく見ると、Sec-Fetch-*
で始まる3つのヘッダがあります。
これに注意が向き、これらのヘッダを設定していないし、他の関数を適用していないのに、どうしてこれらのヘッダが自動的に追加されたのか疑問に思いました。おそらくブラウザが関与しているのだろうと推測しました。
Googleで調べてみると、これは**Fetch Metadata Request Headers**という新しい草案であることがわかりました。現時点では、これらのヘッダはChromeのみが追加しますが、FirefoxやSafariでは追加されません。
同一生成元ポリシー(CORS)について再考する
私たちは、悪意のある人々が奇妙な手法でデータを盗むのを防ぐために、ブラウザが特定のソースへのアクセス条件を制限していることを知っています。例えば、クロスドメインリクエストでは Access-Control-Allow-Origin
やプリフライトリクエストなどを追加する必要があります。詳細な内容は、以前に私が書いた「CORSとCookieの取り扱い方」を参照してください。
しかし、それでもいくつかの欠陥があります。たとえば、<img/>
はまだクロスドメインリクエストを送信できるため、悪意のある人々はCORSの制限を回避することができます。もちろん、サーバーが基本的な保護措置を取っている場合、大部分の安全でないリクエストをブロックすることができます。
リクエストを送信する際に、このリクエストがどこから来たのかを示すいくつかの追加のヘッダ情報(メタデータ)を付けることができれば、サーバーはヘッダに基づいて適切な応答を行うことができます。そこで、このような草案が生まれました。
ヘッダの仕様:
現在、草案には主に以下の4つのヘッダがあります:
1. Sec-Fetch-Dest
このリクエストの目的地を表します。
可能な値には、audio、document、font、image、object、serviceworker などがあります。これらのヘッダによる判定があることで、サーバーはすぐにこのリクエストのソースが合法かどうかを判断することができます。たとえば、このソースが <img>
から来ていて、サーバーに画像を要求していない場合、ほぼ間違いなくハッカーですので、エラーを直接返すことができます。
2. Sec-Fetch-Mode
リクエストのモードを表します。cors、navigate、nested-navigate、no-corsなどが主な値です。このリクエストのモードが何であるかを判断するためのもので、fetch
のモードに似ています。
Set-Fetch-User
のようなものを使用することで、リクエストが操作(クリック、キーボードなど)によって行われたかどうかもわかります。
3. Sec-Fetch-Site
リクエストのソースが同一生成元かクロスドメインかを示します。
4. Sec-Fetch-User
このヘッダの値はブール値であり、リクエストがnavigation request(リクエストの目的地がドキュメントである)であり、かつ対話がある場合(ボタンをクリックしたり、キーボードを操作したりなど)、trueになります。サーバーはこのヘッダを使用して、ユーザーがリクエストをトリガーする方法が合法かどうかを判断することができます。
たとえば、フォームを送信するときは、リクエストがドキュメントから送信され、かつユーザーが対話(ボタンをクリックして送信するなど)しているため、Set-Fetch-User
は?T
になります。
ヘッダを削除する方法はありますか?
これが規格の一部になる場合、削除する方法はないかもしれません。また、ヘッダの値を手動で変更することもできません。なぜなら、それはforbidden headersの一部だからです。
結論
これまで同様のことを実現するためには、カスタムヘッダを使用して防御する必要がありましたが、それでも偽造される可能性があり、カスタムヘッダを追加するためにはプリフライトのチェックが必要で、手間がかかりました。仕様に基づくアプローチの利点は、これらのヘッダが簡単に書き換えられないことと、統一された標準が提供されることです。これらのヘッダがあれば、バックエンドはリクエストを受け取った際により多くの判断を行い、セキュリティを向上させることができます。