HTTP ヘッダーは、キャッシュとブラウザが Web コンテンツを処理するプロセスをコントロールするための重要な方法です。しかし、その多くは誤った使い方がされていたり、無意味に使用されています。そのため、ページを読み込む大事なタイミングでオーバーヘッドが追加され、意図したように機能しない可能性があります。ヘッダーのベストプラクティスに関するシリーズのこの第1弾では、不要なヘッダーについて取り上げます。
ほとんどの開発者は、さまざまな HTTP ヘッダーに関する知識を有し、それらを活用してコンテンツを機能させています。最もよく知られている HTTP ヘッダーとして `Content-Type` や `Content-Length` があり、これらは広く普及しています。しかし、最近になってセキュリティの改善を目的とした `Content-Security-Policy` や `Strict-Transport-Security`、パフォーマンスの向上を目的とした `Link rel=preload` などのヘッダーが使用され始めました。これらの新しいヘッダーはさまざまなブラウザで幅広くサポートされているにもかかわらず、ほとんどのサイトで使用されていません。
一方、人気があるにもかかわらず、古くて実際にはそれほど役に立たないヘッダーも多数あります。このことは [HTTP Archive](http://httparchive.org/) で証明されています。これは Google が運営し、Fastly がスポンサーを務めるプロジェクトで、[WebPageTest](https://www.webpagetest.org/) を使用して毎月50万件の Web サイトを読み込み、結果を [BigQuery](https://cloud.google.com/bigquery/) で利用しています。
HTTP Archive のデータを基に、最も人気のある30個のレスポンスヘッダー (各ヘッダーを使用するアーカイブ内のドメイン数に基づく) とその有益性を以下に示します。
Header name |
リクエスト |
Domains |
Status |
date | 48779277 | 535621 | Required protocol |
content-type | 47185627 | 533636 | Usual required browser |
server | 43057807 | 519663 | Unnecessary |
content-length | 42388435 | 519118 | Useful |
last-modified | 34424562 | 480294 | Useful |
cache-control | 36490878 | 412943 | Useful |
etag | 23620444 | 412370 | Useful |
content-encoding | 16194121 | 409159 | Required for compress content |
expires | 29869228 | 360311 | Unnecessary |
x-powered-by | 4883204 | 211409 | Unnecessary |
pragma | 7641647 | 188784 | Unnecessary |
x-frame-options | 3670032 | 105846 | Unnecessary |
access-control-allow-origin | 11335681 | 103596 | Useful |
x-content-type-options | 11071560 | 94590 | Useful |
link | 1212329 | 87475 | Useful |
age | 7401415 | 59242 | Useful |
x-cache | 5275343 | 56889 | Unnecessary |
x-xss-protection | 9773906 | 51810 | Useful |
strict-transport-security | 4259121 | | 51283Useful |
via | 4020117 | 47102 | Unnecessary |
p3p | 8282840 | 44308 | Unnecessary |
expect-ct | 2685280 | 40465 | Useful |
content-language | 334081 | 37927 | Debatable |
x-aspnet-version | 676128 | 33473 | Unnecessary |
access-control-allow-credentials | 2804382 | 30346 | Useful |
x-robots-tag | 179177 | 24911 | Not relevant to browsers |
x-ua-compatible | 489056 | 24811 | Unnecessary |
access-control-allow-methods | 1626129 | 20791 | Useful |
access-control-allow-headers | 1205735 | 19120 | Useful |
次に、不要なヘッダーとその理由、および対応方法について見てみましょう。
## 価値のないヘッダー (server、x-powered-by、via)
開発者は自身が選択したサーバーソフトウェアに誇りを持っているかもしれませんが、ほとんどの人にとっては意味がありません。最悪の場合、これらのヘッダーが重要なデータの漏えいを招き、サイトが攻撃にさらされやすくなります。
```
Server: apache
X-Powered-By: PHP/5.1.1
Via: 1.1 varnish, 1.1 squid
```
[RFC7231](https://httpwg.org/specs/rfc7231.html#header.server) では、コンテンツの配信に使用するソフトウェアを識別する `Server` ヘッダーをサーバーがレスポンスに含めることを認めています。最も一般的なのは「apache」や「nginx」などの文字列です。このヘッダーの使用は許可されていますが必須ではなく、開発者やエンドユーザーにとってはほとんど価値がありません。それにもかかわらず、今日の Web において `Server` ヘッダーは3番目にもっともよく使用されている HTTP レスポンスヘッダーです。
`X-Powered-By` は上記のリストで、どの標準でも定義されていないヘッダーとしては最も人気のあるヘッダーで、`Server` ヘッダーと似たような目的を持っていますが、通常は Web サーバーの背後にあるアプリケーションプラットフォームを示します。一般的な値は「ASP.net」や「PHP」、「Express」などです。このヘッダーにも具体的なメリットはなく、単にスペースを占めるだけです。
`Via` は上記の2つよりも議論の余地があると思われます。プロキシを識別するため、すべてのプロキシがこのヘッダーを*リクエスト*に追加するよう ([RFC7230 によって](https://httpwg.org/specs/rfc7230.html#header.via)) 規定されているためです。プロキシのホスト名を指定することもできますが、「vegur」、「varnish」、「squid」などの汎用的な識別子が指定される傾向があります。リクエストでこのヘッダーを削除する (または設定しない) と、[プロキシ転送ループ](http://www.icir.org/vern/papers/cdn-loops.NDSS16.pdf)が発生する可能性があります。しかし興味深いことに、このヘッダーはブラウザに対するレスポンスにもコピーされます。ブラウザでは情報提供の目的にのみ使用され、何らかの処理に使用されることはないため削除しても特に問題はありません。
## 推奨されない標準 (P3P、Expires、X-Frame-Options、X-UA-Compatible)
もう1つのカテゴリーとして、ブラウザでは効果があるものの、その効果を実現するための最適な方法ではない (または最適ではなくなった) ヘッダーがあります。
```
P3P: cp="this is not a p3p policy"
Expires: Thu, 01 Dec 1994 16:00:00 GMT
X-Frame-Options: SAMEORIGIN
X-UA-Compatible: IE=edge
```
`P3P` は奇妙な生き物です。私はこのヘッダーが何であるのか知りませんでした。そして、さらに興味深いのは最も一般的な値の1つが「this is not a p3p policy」であることです。これでは P3P なのか P3P ではないのかはっきりしません。
話は[コンピューターによる読み取りが可能なプライバシーポリシーの標準化の試み](https://en.wikipedia.org/wiki/P3P#User_agent_support)に遡ります。データの表示方法はブラウザごとに異なり、Internet Explorer (IE) はこのヘッダーを実装した唯一のブラウザでした。その IE においても `P3P` はユーザーに対して視覚上の効果をもたらしていたわけではなく、iframe でサードパーティの Cookie へのアクセスを許可するために必要なだけでした。一部のサイトでは、[法的に問題がある可能性](https://www.cylab.cmu.edu/_files/pdfs/tech_reports/CMUCyLab10014.pdf)があるにもかかわらず、前述のような非準拠の P3P ポリシーを設定しています。
言うまでもなく、サードパーティの Cookie を読み取ることは通常は良くない考えであり、それをするつもりがないのであればわざわざ `P3P` ヘッダーを設定する必要はありません。
20年にわたり `Cache-Control` が `Expires` よりも優先されてきたことを考えると、`Expires` の人気の高さはまさに驚きです。`Cache-Control` ヘッダーに `max-age` ディレクティブが含まれている場合、同じレスポンスの `Expires` ヘッダーは無視されます。しかし、莫大な数のサイトが両方のヘッダーを設定しており、通常 `Expires` ヘッダーには `Thu, 01 Dec 1994 16:00:00` GMT という値が設定されます。これは、コンテンツがキャッシュされないようにするためであり、[仕様から](https://www.ietf.org/rfc/rfc2616.txt)サンプルの日付をコピーアンドペーストすることでその目的を確実に達成できます。
![Screen Shot 2018-05-10 at 21.49.25](//images.ctfassets.net/6pk8mg3yh2ee/63zsHXNxp6YmWacesKYgwy/e3f1040e2d948b0655667aaa86d5310f/Screen_Shot_2018-05-10_at_21.49.25.png)
しかし、そうする理由はありません。`Expires` ヘッダーに過去の日付を指定している場合は、以下のヘッダーに置き換えてください。
```
Cache-Control: no-store, private
```
(`no-store` は、コンテンツを永続ストレージに書き込まないようにするための非常に強力なディレクティブです。そのため、前後へのナビゲーションや休止状態のタブの再開時など、ユースケースによってはパフォーマンスを考慮して `no-store` を指定する方がよい場合もあります。)
サイトを監査するツールの一部では、`X-Frame-Options` ヘッダーを追加し、値を ‘SAMEORIGIN’ に設定するよう求められることがあります。これにより、別のサイトによるフレーム内の表示を拒否するようブラウザに指示されます。これは通常、[クリックジャッキング](https://en.wikipedia.org/wiki/Clickjacking)に対する優れた防御策になります。しかし、以下のように指定することで同じ効果が得られるだけでなく、より一貫性のあるサポートと信頼性の高い動作の定義を利用できます。
```
Content-Security-Policy: frame-ancestors 'self'
```
この方法には、他の理由 (詳細は後述) で必要なヘッダー (CSP) を兼ねるというメリットがあります。したがって、最近では `X-Frame-Options` を使用しなくても通常、問題ありません。
最後に、Microsoft が IE9 に「互換表示」を導入した際、ユーザーが IE9 を使用して閲覧していても、ブラウザ側がページを正しく表示するためには以前のバージョンが必要であると判断した場合、IE8 または IE7 のエンジンを使用してページがレンダリングされる可能性がありました。このようなヒューリスティックは必ずしも正しいわけではなく、開発者は `X-UA-Compatible` ヘッダーやメタタグを使用してこれらをオーバーライドすることが可能でした。実際、Bootstrap と同様に、このヘッダーは次第にフレームワークの標準のパーツとして使用されるようになりました。最近では、このヘッダーでできることはほとんどなく、このヘッダーを認識できるブラウザを使用しているユーザーもわずかです。サイトのメンテナンスを積極的に実施している場合、互換表示を動作させるテクノロジーを使用している可能性はほとんどないでしょう。
## デバッグデータ (X-ASPNet-Version、X-Cache)
驚くべきことに、一般的に使用されている最も人気のヘッダーの一部はどの標準にも規定されていません。つまり、どういうわけか何千もの Web サイトが特定のヘッダーを特定の方法で使用することに自然に同意していると考えられるのです。
```
X-Cache: HIT
X-Request-ID: 45a336c7-1bd5-4a06-9647-c5aab6d5facf
X-ASPNet-Version: 3.2.32
X-AMZN-RequestID: 0d6e39e2-4ecb-11e8-9c2d-fa7ae01bbebc
```
実際には、このような「未知の」ヘッダーは Web サイトの開発者が個別に、かつ自主的に作成したものではありません。通常は、特定のサーバーフレームワーク、ソフトウェア、または特定のベンダーのサービス (上記の例の最後のヘッダーは AWS で使用される一般的なヘッダーです) を使用するために作り出されたものです。
具体的には、`X-Cache` は Fastly が他の Fastly 関連のヘッダー (`X-Cache-Hits` や `X-Served-By` など) と共に追加したヘッダーです (他の CDN でも同様のヘッダーを追加しています)。デバッグが有効になっている場合、`Fastly-Debug-Path` や`Fastly-Debug-TTL` などのヘッダーも追加されます。
これらのヘッダーはすべてのブラウザで認識されるわけではなく、削除してもページのレンダリングのプロセスに違いは生じません。しかし、これらのヘッダーは開発者に役立つ情報を提供するため、これらをオンにできるようにしておくとよいでしょう。
## 解釈の違い (Pragma)
私は `Pragma` ヘッダーに関する記事を2018年に書くとは思ってもみませんでしたが、HTTP Archive のデータによると、このヘッダーは依然として11位の人気を誇っています。`Pragma` は1997年に非推奨になっただけでなく、もともとレスポンスヘッダーとしての使用を目的としておらず、リクエストの一部としてのみ意味があります。
```
Pragma: no-cache
```
それにもかかわらず、レスポンスヘッダーとしての使用が普及し、一部のブラウザではこのコンテキストでも認識されるほどです。現在、レスポンスのコンテキストで `Pragma` を認識し、`Cache-Control` を認識しないキャッシュをレスポンスが通過する可能性はほぼゼロに等しいです。何らかのコンテンツをキャッシュされないようにしたいのであれば、`Cache-Control: no-store, private` と指定するだけですみます。
## 非ブラウザ (X-Robots-Tag)
上位30件のレスポンスヘッダーのひとつに非ブラウザのヘッダーがあります。`X-Robots-Tag` は、Google や Bing のボットなどのクローラーによって使用されるためのものです。ブラウザに対しては意味を持たないため、リクエスト元のユーザーエージェントがクローラーの場合にのみこのヘッダーを設定するのは問題ありません。一方、このヘッダーの使用によりテストが困難になり、検索エンジンのサービス利用規約に違反することもあり得ます。
## バグ
最後はシンプルなバグに特別賞を贈りたいと思います。*リクエスト*に `Host` ヘッダーがあるのは理にかなっていますが、レスポンスにこのヘッダーが使用されている場合、サーバーに何らかの設定ミスがある可能性を示しています (その設定ミスの詳細をぜひ知りたいです)。ところが、HTTP Archive のデータによると68個のドメインが `Host` ヘッダーをレスポンスで返していました。
## エッジでのヘッダーの削除
幸い、Fastly を利用するサイトでは、[VCL](https://docs.fastly.com/guides/vcl/) でヘッダーを簡単に削除できます。実際に役立つデバッグデータを開発チームが利用できるようにしつつ、一般のユーザーからは隠しておきたいのはよくわかります。この処理は、Cookie や受信 HTTP ヘッダーを検出することで簡単に行うことができます。
次回は、使用すべきヘッダーのベストプラクティス、およびエッジでそれらのヘッダーを実行する方法についてご説明します。