ブログに戻る

フォロー&ご登録

The headers we don't want

Andrew Betts

Principal Developer Advocate, Fastly

HTTP ヘッダーは、キャッシュとブラウザが Web コンテンツを処理するプロセスをコントロールするための重要な方法です。しかし、その多くは誤った使い方がされていたり、無意味に使用されています。そのため、ページを読み込む大事なタイミングでオーバーヘッドが追加され、意図したように機能しない可能性があります。ヘッダーのベストプラクティスに関するシリーズのこの第1弾では、不要なヘッダーについて取り上げます。

ほとんどの開発者は、さまざまな HTTP ヘッダーに関する知識を有し、それらを活用してコンテンツを機能させています。最もよく知られている HTTP ヘッダーとして Content-TypeContent-Length があり、これらは広く普及しています。しかし、最近になってセキュリティの改善を目的とした Content-Security-PolicyStrict-Transport-Security、パフォーマンスの向上を目的とした Link rel=preload などのヘッダーが使用され始めました。これらの新しいヘッダーはさまざまなブラウザで幅広くサポートされているにもかかわらず、ほとんどのサイトで使用されていません。

一方、人気があるにもかかわらず、古くて実際にはそれほど役に立たないヘッダーも多数あります。このことは HTTP Archive で証明されています。これは Google が運営し、Fastly がスポンサーを務めるプロジェクトで、WebPageTest を使用して毎月50万件の Web サイトを読み込み、結果を BigQuery で利用しています。

HTTP Archive のデータを基に、最も人気のある30個のレスポンスヘッダー (各ヘッダーを使用するアーカイブ内のドメイン数に基づく) とその有益性を以下に示します。

Header name

Requests

Domains

Status

date

48779277

535621

Required by protocol

content-type

47185627

533636

Usually required by 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 compressed 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

51283

Useful

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 では、コンテンツの配信に使用するソフトウェアを識別する Server ヘッダーをサーバーがレスポンスに含めることを認めています。最も一般的なのは「apache」や「nginx」などの文字列です。このヘッダーの使用は許可されていますが必須ではなく、開発者やエンドユーザーにとってはほとんど価値がありません。それにもかかわらず、今日の Web において Server ヘッダーは3番目にもっともよく使用されている HTTP レスポンスヘッダーです。

X-Powered-By は上記のリストで、どの標準でも定義されていないヘッダーとしては最も人気のあるヘッダーで、Server ヘッダーと似たような目的を持っていますが、通常は Web サーバーの背後にあるアプリケーションプラットフォームを示します。一般的な値は「ASP.net」や「PHP」、「Express」などです。このヘッダーにも具体的なメリットはなく、単にスペースを占めるだけです。

Via は上記の2つよりも議論の余地があると思われます。プロキシを識別するため、すべてのプロキシがこのヘッダーをリクエストに追加するよう (RFC7230 によって) 規定されているためです。プロキシのホスト名を指定することもできますが、「vegur」、「varnish」、「squid」などの汎用的な識別子が指定される傾向があります。リクエストでこのヘッダーを削除する (または設定しない) と、プロキシ転送ループが発生する可能性があります。しかし興味深いことに、このヘッダーはブラウザに対するレスポンスにもコピーされます。ブラウザでは情報提供の目的にのみ使用され、何らかの処理に使用されることはないため削除しても特に問題はありません。

推奨されない標準 (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 ではないのかはっきりしません。

話はコンピューターによる読み取りが可能なプライバシーポリシーの標準化の試みに遡ります。データの表示方法はブラウザごとに異なり、Internet Explorer (IE) はこのヘッダーを実装した唯一のブラウザでした。その IE においても P3P はユーザーに対して視覚上の効果をもたらしていたわけではなく、iframe でサードパーティの Cookie へのアクセスを許可するために必要なだけでした。一部のサイトでは、法的に問題がある可能性があるにもかかわらず、前述のような非準拠の P3P ポリシーを設定しています。

言うまでもなく、サードパーティの Cookie を読み取ることは通常は良くない考えであり、それをするつもりがないのであればわざわざ P3P ヘッダーを設定する必要はありません。

20年にわたり Cache-ControlExpires よりも優先されてきたことを考えると、Expires の人気の高さはまさに驚きです。Cache-Control ヘッダーに max-age ディレクティブが含まれている場合、同じレスポンスの Expires ヘッダーは無視されます。しかし、莫大な数のサイトが両方のヘッダーを設定しており、通常 Expires ヘッダーには Thu, 01 Dec 1994 16:00:00 GMT という値が設定されます。これは、コンテンツがキャッシュされないようにするためであり、仕様からサンプルの日付をコピーアンドペーストすることでその目的を確実に達成できます。

しかし、そうする理由はありません。Expires ヘッダーに過去の日付を指定している場合は、以下のヘッダーに置き換えてください。

Cache-Control: no-store, private

(no-store は、コンテンツを永続ストレージに書き込まないようにするための非常に強力なディレクティブです。そのため、前後へのナビゲーションや休止状態のタブの再開時など、ユースケースによってはパフォーマンスを考慮して no-store を指定する方がよい場合もあります。)

サイトを監査するツールの一部では、X-Frame-Options ヘッダーを追加し、値を ‘SAMEORIGIN’ に設定するよう求められることがあります。これにより、別のサイトによるフレーム内の表示を拒否するようブラウザに指示されます。これは通常、クリックジャッキングに対する優れた防御策になります。しかし、以下のように指定することで同じ効果が得られるだけでなく、より一貫性のあるサポートと信頼性の高い動作の定義を利用できます。

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-HitsX-Served-By など) と共に追加したヘッダーです (他の CDN でも同様のヘッダーを追加しています)。デバッグが有効になっている場合、Fastly-Debug-PathFastly-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 でヘッダーを簡単に削除できます。実際に役立つデバッグデータを開発チームが利用できるようにしつつ、一般のユーザーからは隠しておきたいのはよくわかります。この処理は、Cookie や受信 HTTP ヘッダーを検出することで簡単に行うことができます。

次回は、使用すべきヘッダーのベストプラクティス、およびエッジでそれらのヘッダーを実行する方法についてご説明します。