dorapon2000’s diary

忘備録的な。セキュリティとかネットワークすきです。

HLSのHTTPヘッダを見る

HLSのHTTPヘッダを見てみたいというリクエストがあったのでHLSのヘッダを見てみる。

HLS

HLSはHTTP Live Streamingの略で、Appleが提案したストリーミング配信の仕組み。ネットワークの帯域を考慮して配信する動画の画質を配信中に切り替えられ、現在はニコ動やYoutube、Abemaなどで広く利用されている。

HLSは2種類のファイルから構成される

  • m3u8:取得するセグメントを記したインデックスファイル
  • ts:動画を断片化したセグメントファイル

Chromeの開発者ツールでAbemaのそれぞれのファイルのHTTPヘッダを確認した。

m3u8ファイル

f:id:dorapon2000:20201106220331p:plain

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 217
X-Akamai-Path-Stats: [3:1068:47932],[1:9793:7207],[1:16613:387],[1:14838:31162],[1:20680:4294957616]
Cache-Control: max-age=30
Date: Thu, 05 Nov 2020 14:22:55 GMT
Connection: keep-alive
Vary: Accept-Encoding
Akamai-Mon-Iucid-Del: 626621
Content-Type: application/x-mpegURL
Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Server,range,hdntl,hdnts,Akamai-Mon-Iucid-Ing,Akamai-Mon-Iucid-Del,Akamai-Request-BC
Access-Control-Allow-Headers: origin,range,hdntl,hdnts
Access-Control-Allow-Methods: GET,OPTIONS
Access-Control-Allow-Origin: *

HTTPバージョン

HTTP/1.1 200 OK

AbemaはHTTP/2で通信をしているが、m3u8ファイルとtsファイルはHTTP/1.1で取得していた。AbemaのHLSファイルはAkamaiCDNから配信されているため、CDNが単にHTTP/2対応してなかった可能性もあるが、HLSとHTTP/2は相性が悪いのではないかとも思った。

HTTP/2はファイルダウンロードの並列数を増やして全体的なパフォーマンスをあげる代わりに、1つのファイルあたりのダウンロード時間は長くなっている。ストリーミング配信ではページを開いてから再生できるまでの時間が短いほうがよいわけで、1ファイルのダウンロードに時間がかかるのは相性が悪いのかもしれない。

あるいは、HTTP/2のパケロスによるパフォーマンス低下をケアしたのかもしれない。HTTP/2は単一TCPコネクションの中で擬似的に複数のファイルストリームを作り、並列にダウンロードできる。しかし、単一TCPコネクションであるがゆえに、どこかのストリームでパケロスするとTCP輻輳窓が落ち、すべてのストリームで送信速度が低下する。後ろで再生するtsファイルのパケロスで今欲しいtsファイルのダウンロードが遅れては悲しすぎる。

同じ疑問がStackoverFlowで投稿されていた。

stackoverflow.com

With video streaming, there are not that many concurrent small requests - instead the client fetches larger chunks piece by piece. This should work pretty fine on top of HTTP/1.1 connections with keep-alive

(動画ストリーミングにおいては、小さなリクエストが並列に実行されるわけではなく、大きなチャンクで1つずつ取得される。この場合HTTP/1.1のkeep-aliveのほうがより優れた性能を発揮するはずだ。)

こちらの回答がそれっぽいが、なぜ優れた性能を発揮するのか理由がよくわからなかった。性能としては同じくらいにならないのだろうか。

Content-Encoding

Content-Encoding: gzip

コンテンツの圧縮方式をgzipで指定している。jpg画像などはすでに圧縮されているため、さらに圧縮すると逆に容量が増えてしまうため注意が必要。

Cache-Control

Cache-Control: max-age=30

30秒だけキャッシュしてよいとしている。動画は変わるものではないのだから、30秒といわず1日キャッシュして良い気がするが問題があるのだろうか。

Connection

Connection: keep-alive

HTTPのコネクションがKeep-Aliveであることを意味する。動画の再生に応じてtsファイルをダウンロードする必要があるのだから、コネクションは毎回やり直したくないという意味。なお、HTTP/2の場合keep-aliveしてはいけない*1

Content-Type

Content-Type: application/x-mpegURL

RFC8216では、必ずapplication/vnd.apple.mpegurlaudio/mpegurlでなくてはいけないとあるが、Abemaでは独自にMIMEを定義しているようだった。x-というのはかつて非公式なHTTPヘッダにつけられていたサフィックスと同じで、独自MIMEをあえてつけていることになにか理由があるのかも知れない。

In the second, the HTTP Content-Type MUST be "application/vnd.apple.mpegurl" or "audio/mpegurl".

CORS

Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Server,range,hdntl,hdnts,Akamai-Mon-Iucid-Ing,Akamai-Mon-Iucid-Del,Akamai-Request-BC
Access-Control-Allow-Headers: origin,range,hdntl,hdnts
Access-Control-Allow-Methods: GET,OPTIONS
Access-Control-Allow-Origin: *

CORSはオリジン間リソース共有のことで、XSSCSRF対策の1つ。仕組みは徳丸先生の動画がとても参考になったためそちらに譲る。

理解しきれていないので間違っているかもしれない。

tsファイル

f:id:dorapon2000:20201107032936p:plain

HTTP/1.1 200 OK
Content-Length: 421888
Date: Fri, 06 Nov 2020 16:54:18 GMT
Connection: keep-alive
Akamai-Mon-Iucid-Del: 655733
Content-Type: video/MP2T
Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Server,range,hdntl,hdnts,Akamai-Mon-Iucid-Ing,Akamai-Mon-Iucid-Del,Akamai-Request-BC
Access-Control-Allow-Headers: origin,range,hdntl,hdnts
Access-Control-Allow-Methods: GET,OPTIONS
Access-Control-Allow-Origin: *

m3u8との相違点

まとめ

HLSの場合HTTP/2を使わないというのも、こうやって調べないと気づけなかった。また、何でもかんでも圧縮すればいいわけではないこともわかった。勉強になる。

参考

HLS動画ストリームの確認方法 - Qiita

HTTP Live Streaming - Wikipedia

Is it possible to do HLS streaming over HTTP/2, and will it be better latency-wise than over HTTP/1.1? - Stack Overflow

オリジン間リソース共有 (CORS) - HTTP | MDN

CORSまとめ - Qiita

CORSの原理を知って正しく使おう - YouTube

【小ネタ】CloudFront のファイル圧縮機能で HLS コンテンツが圧縮されるのか調べてみた | Developers.IO

GoogleのHTTPヘッダを見る

HTTPヘッダを見るシリーズ第3弾はGoogle。気になるヘッダをMDN Web docsやグーグル先生で調べていく。

dorapon2000.hatenablog.com

dorapon2000.hatenablog.com

ヘッダ全体

$ curl -XGET -I https://www.google.com
HTTP/2 200
date: Wed, 04 Nov 2020 14:35:29 GMT
expires: -1
cache-control: private, max-age=0
content-type: text/html; charset=ISO-8859-1
p3p: CP="This is not a P3P policy! See g.co/p3phelp for more info."
server: gws
x-xss-protection: 0
x-frame-options: SAMEORIGIN
set-cookie: 1P_JAR=2020-11-04-14; expires=Fri, 04-Dec-2020 14:35:29 GMT; path=/; domain=.google.com; Secure
set-cookie: NID=204=XXXX; expires=Thu, 06-May-2021 14:35:29 GMT; path=/; domain=.google.com; HttpOnly
alt-svc: h3-Q050=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
accept-ranges: none
vary: Accept-Encoding

Expires

expires: -1

Expiresで有効期限切れにする方法は、過去の日付の指定以外に、無効な日付であっても成立する。0でもよいはずだが-1を指定していた。

Cache-Control

cache-control: private, max-age=0

privateな情報を扱うため、プロキシなどの共有キャッシュには残してはいけないが、個人のブラウザのキャッシュには残しても良い。ただし、max-age=0なため即座に有効期限切れになり、ブラウザは毎回サーバにキャッシュが古くないかIf-Modified-Sinceヘッダをつけてリクエストを飛ばす(検証する)必要がある。という意味。もし古くなってなければ304 Not Modifiedレスポンスが返ってきて、キャッシュを使うことができる。

個人のブラウザのキャッシュすら禁止したい場合はno-storeを使う。

Content-Type

content-type: text/html; charset=ISO-8859-1

curlで取得するとcharsetがISO-8859-1(ラテン語)になる。chromeで確かめるとISO-8859-1ではなくutf-8が使われていた(?)

f:id:dorapon2000:20201105013017p:plain

いろいろ試した結果、User-AgentヘッダをChromeのものにしたらcharsetがutf-8になった。

$ curl -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36" -XGET -I https://www.google.com
HTTP/2 200
content-type: text/html; charset=UTF-8

GoogleはUser-Agentでcharsetを変えるらしい。

P3P

p3p: CP="This is not a P3P policy! See g.co/p3phelp for more info."

P3PはPlatform for Privacy Preferencesのことで、そのサイトがユーザーの個人情報をどう扱うかを表明したもの、とのこと。facebookの説明によると、現在は形骸化しているらしい。おそらくP3Pに記述されたポリシーに従って、ブラウザがサイトを拒否したりしなかったりする未来を考えていたのだと思う。CPはコンパクトポリシーの略で本来であれば特定のポリシーを表す略語が入るが、GoogleP3Pへのリンクを貼っている。

P3PW3C (World Wide Web Consortium)が策定した標準規格ですが、最新のウェブブラウザーのほとんどがP3Pを完全にはサポートしなくなったため、この標準化作業は数年前に中断されました。その結果、P3Pは時代遅れの規格となり、ウェブで現在使われている技術を反映していないため、ほとんどのウェブサイトがP3Pポリシーを採用していないのが現状です。

FacebookにおけるPSP (Platform for Privacy Preferences)の利用 | Facebookヘルプセンター | Facebook

Alt-Svc

alt-svc: h3-Q050=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"

GoogleはHTTP/3を導入しているため、h3で接続してもいいとAlt-Svcでブラウザに伝えている。

Accept-Ranges

accept-ranges: none

「ファイルの一部だけ取得する」ということができないことを表す。一部だけ取得するの意味がわかりづらいので、取得できる場合をコマンドで確認すると以下のようになる。

$ curl https://i.imgur.com/z4d4kWk.jpg -i -H "Range: bytes=0-1023"
HTTP/2 206
content-type: image/jpeg
accept-ranges: bytes
content-range: bytes 0-1023/146515

Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.

$ curl https://i.imgur.com/z4d4kWk.jpg -i -H "Range: bytes=0-1023" --output pic.jpg

$ file pic.jpg
pic.jpg: data

画像の先頭1014バイトだけ取得している。ステータスコードの206はPartial Contentで部分的なファイルのレスポンスを表す。なお、中途半端なのでファイルに落とし込んだとしても壊れて開けない。用途として、ファイルダウンロードを中断後にサーバが対応していればAccept-Rangesによって再開できる。

Googleのヘッダの話に戻り、Accept-Rangesがなければnoneと同じ意味になるが、Googleはあえて明示しているようだ。

まとめ

p3pというおもしろいヘッダと出会えたし、ファイルダウンロードの再開の仕組みもわかった。また、過去の調べたTwitterFacebookとの共通点はx-xss-protection: 0であること。XSSの予防につながるのだから1で良い気がするが、なぜどこも0なのだろうか。こういう気づきも面白い。

参考

HTTPヘッダチューニング Expiresヘッダについて | REDBOX Labo

HTTPヘッダチューニング Etag・Last-Modified | REDBOX Labo

キャッシュさせたらあかーん!ヘッダーの設定方法 - IDCF テックブログ

IPA ISEC セキュア・プログラミング講座:Webアプリケーション編 第5章 暴露対策:プロキシキャッシュ対策

HTTP キャッシュおさらい - LCL Engineers' Blog

そのクロスドメインでcookie使えてますか? - Qiita

FacebookにおけるPSP (Platform for Privacy Preferences)の利用 | Facebookヘルプセンター | Facebook

HTTP 範囲リクエスト - HTTP | MDN

facebookのHTTPヘッダを読む

前回はtwitterのHTTTPヘッダを読んだので、今回はfacebookを読んでいく。前回とカブる部分は飛ばす。

dorapon2000.hatenablog.com

ヘッダ全体

$ curl -I -XGET https://www.facebook.com/
HTTP/2 200
vary: Accept-Encoding
pragma: no-cache
cache-control: private, no-cache, no-store, must-revalidate
expires: Sat, 01 Jan 2000 00:00:00 GMT
set-cookie: fr=XXXX; expires=Tue, 02-Feb-2021 11:33:15 GMT; Max-Age=7775999; path=/; domain=.facebook.com; secure; httponly
set-cookie: sb=XXXX; expires=Fri, 04-Nov-2022 11:33:16 GMT; Max-Age=63072000; path=/; domain=.facebook.com; secure; httponly
strict-transport-security: max-age=15552000; preload
x-content-type-options: nosniff
x-xss-protection: 0
x-frame-options: DENY
content-type: text/html; charset="utf-8"
x-fb-debug: XXXX
date: Wed, 04 Nov 2020 11:33:16 GMT
alt-svc: h3-29=":443"; ma=3600,h3-27=":443"; ma=3600

Vary

vary: Accept-Encoding

同一オリジンで同一ファイルへのアクセスだとしても、Accept-Encodingヘッダが異なる場合は別のファイルとして認識してキャッシュしないという意味。ブラウザとサーバの間にキャッシュサーバがあるとき、Varyヘッダを指定されたものは異なるファイルとしてキャッシュされる。

x-fb-debug

Debugging - グラフAPI - ドキュメンテーション - Facebook for Developers

名前の通り、Facebookデバッグのために利用されると説明されている。

Alt-Svc

alt-svc: h3-29=":443"; ma=3600,h3-27=":443"; ma=3600

HTTP/3のdraft29で同じドメインの443ポートでもアクセスできるということを知らせている。同様にh3-27でも。maはmax-ageの略でalt-svcを有効にする時間。

ドメインを指定する場合は次のようになる。

Alt-Svc: h2="alt.example.com:443", h2=":443"

実際にHTTP3でも通信できるか確認してみた。HTTP3の通信には以下のサイトを参考にした。

HTTP/3 対応の curl を作る - Qiita

❯ docker run --rm keioni/curl-http3 curl -Iv --http3 https://www.facebook.com
略
HTTP/3 200
vary: Accept-Encoding
pragma: no-cache
cache-control: private, no-cache, no-store, must-revalidate
expires: Sat, 01 Jan 2000 00:00:00 GMT
set-cookie: fr=XXXX; expires=Tue, 02-Feb-2021 13:26:39 GMT; Max-Age=7775999; path=/; domain=.facebook.com; secure; httponly
set-cookie: sb=XXXX; expires=Fri, 04-Nov-2022 13:26:40 GMT; Max-Age=63072000; path=/; domain=.facebook.com; secure; httponly
strict-transport-security: max-age=15552000; preload
x-content-type-options: nosniff
x-xss-protection: 0
x-frame-options: DENY
content-type: text/html; charset="utf-8"
x-fb-debug: XXXX
date: Wed, 04 Nov 2020 13:26:40 GMT
alt-svc: h3-29=":443"; ma=3600,h3-27=":443"; ma=3600

ちゃんとできている。HTTP/3にしてもヘッダは変わっていない。alt-svcで提案されるh3の片方は消えるのかと思ったけれど、そんなことはなかった。

おわりに

twitterとは同じ部分も違う部分もあった。

twitterではCSPが書かれていたがfacebookにはヘッダすらなかった。CSPを丁寧に書くとヘッダが膨らむためケアしたのかもしれない。一方、X-Content-Type-Options: nosniffX-Frame-Options: DENYはどちらにも存在した。こちらのほうがセキュリティ的な重要度が高いとどちらも認識しているのだと思う。

googleはどうだろう。次はgoogleのヘッダを見てみたい。

参考

HTTP Varyヘッダについて | Rの技術メモ

Fastly で Varyヘッダーを活用する - Qiita

twitterのHTTPヘッダを読む

HTTPヘッダを雰囲気で読んでしまっている。実際にどんなヘッダが使われていて、どのように使われているか調べてみるため、twitterのHTTPヘッダをMDN Web docsと照らし合わせながら1つずつ見てみた。セキュリティ的に公開してはいけなさそうな部分はXXXXとしている。

ヘッダ全体

$ curl -I -XGET https://twitter.com/
HTTP/2 200
cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0
content-security-policy: connect-src 'self' blob: https://*.giphy.com https://*.pscp.tv https://*.video.pscp.tv 省略 ; default-src 'self'; form-action 'self' https://twitter.com 省略; font-src 'self' https://*.twimg.com; frame-src 'self' https://twitter.com 省略 ; img-src 'self' blob: data: https://*.cdn.twitter.com 省略; manifest-src 'self'; media-src 'self' blob: 省略; object-src 'none'; script-src 'self' 'unsafe-inline' https://*.twimg.com 省略 'nonce-MThhNzMwYjItNmI2ZS00YmNiLTgyNjctYzNhNDJmNjhmNTE0'; style-src 'self' 'unsafe-inline' https://*.twimg.com; worker-src 'self' blob:; report-uri https://twitter.com/i/csp_report?a=O5RXE%3D%3D%3D&ro=false
content-type: text/html; charset=utf-8
cross-origin-opener-policy: same-origin
date: Tue, 03 Nov 2020 13:37:45 GMT
expiry: Tue, 31 Mar 1981 05:00:00 GMT
last-modified: Tue, 03 Nov 2020 13:37:45 GMT
pragma: no-cache
server: tsa_m
set-cookie: personalization_id="XXXX"; Max-Age=63072000; Expires=Thu, 03 Nov 2022 13:37:45 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None
set-cookie: guest_id=XXXX; Max-Age=63072000; Expires=Thu, 03 Nov 2022 13:37:45 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None
strict-transport-security: max-age=631138519
x-connection-hash: XXX
x-content-type-options: nosniff
x-frame-options: DENY
x-powered-by: Express
x-response-time: 155
x-xss-protection: 0

Cache-Control

cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0

no-storeはキャッシュをしないことを意味する。twitterのような常に情報が流動的なサイトはno-storeにする。

良い例:

Cache-Control: no-store

no-store以外にもいろいろと付いているが、キャッシュをしない場合はこれだけで十分だとMDN Web docsには書かれていた。

pre-check=0, post-check=0はIEのキャッシュ制御用らしい。*1

Content-Security-Policy

見やすく適宜改行した。

content-security-policy: 
  connect-src 'self' blob: https://*.giphy.com https://*.pscp.tv 省略 ; 
  default-src 'self'; 
  form-action 'self' https://twitter.com 省略; 
  font-src 'self' https://*.twimg.com; 
  frame-src 'self' https://twitter.com 省略 ; 
  img-src 'self' blob: data: https://*.cdn.twitter.com 省略; 
  manifest-src 'self'; 
  media-src 'self' blob: 省略; 
  object-src 'none'; 
  script-src 'self' 'unsafe-inline' https://*.twimg.com 省略 'nonce-MThhNzMwYjItNmI2ZS00YmNiLTgyNjctYzNhNDJmNjhmNTE0'; 
  style-src 'self' 'unsafe-inline' https://*.twimg.com; 
  worker-src 'self' blob:; 
  report-uri https://twitter.com/i/csp_report?a=O5RXE%3D%3D%3D&ro=false

特定のサイトのリソースしか読み込ませないためのヘッダ。リソースの種類ごとに細かく指定できる。report-uriはCSP(Content-Security-Policy)違反をしたときにブラウザが報告するURLが示されるが、非推奨でreport-toへと段階的に変更していくようだ。

Content-Type

content-type: text/html; charset=utf-8

おなじみコンテンツタイプヘッダ。charsetについて調べてみた。

仕組みを理解しており、可能であるなら、どのようなコンテンツであれHTTPヘッダーでエンコーディングを指定しましょう。しかし必ず同時に文書内での指定も行うべきです。

HTMLで文字エンコーディングを指定する

指定しないとどうなるかは実装次第のようで、必ず指定したほうがよいようだ。また、<meta>タグにもcharsetが指定できるが、優先度はContent-Typeのcharsetのほうが高い。

Cross-Origin-Opener-Policy

cross-origin-opener-policy: same-origin

twitterから別のサイトを開いたときに、別のサイトがwindow.openerからtwitterのプロパティを読み込めてしまうのはセキュリティ上よろしくないため、それを許可しないという意味。詳しくは以下のサイトを参照。

asnokaze.hatenablog.com

Date

date: Tue, 03 Nov 2020 13:37:45 GMT

日付。禁止ヘッダーと言われ、ユーザーエージェントが自動挿入するヘッダで、アプリケーション側で特定の日付を指定したりはできない。

expiry???

expiry: Tue, 31 Mar 1981 05:00:00 GMT

有効期限を示すExpiresならあるが、expiryは謎。twitterが独自に利用しているヘッダ?expiresのtypoだとしても、Cache-Controlでno-storeが指定されているため、コンテンツがキャッシュされることはない。

Last-Modified

last-modified: Tue, 03 Nov 2020 13:37:45 GMT

オリジンがそのファイルを最後に更新したとする日時が入る。If-Modified-Sinceなどで利用される。

Pragma

pragma: no-cache

現在HTTP/1.0との広報互換性のために利用されるヘッダで、ここではCache-Control: no-storeと同じことを表している。おそらく未だHTTP/1.1対応すらしていないブラウザが一定数あるのだろう。

Server

server: tsa_m

レスポンスを返したサーバで動くソフトウェアを表している。詳細に書くと攻撃に利用される可能性があるため、あまり詳細に記述しないほうがよい。tsa_mが何のソフトウェアを表しているかはよくわからなかった。

Set-Cookie

見やすいように適宜改行した。

set-cookie: 
  personalization_id="XXXX"; 
  Max-Age=63072000; 
  Expires=Thu, 03 Nov 2022 13:37:45 GMT; 
  Path=/; 
  Domain=.twitter.com; 
  Secure; 
  SameSite=None

Cookieをセットしている。

  • personalization_idだけがCookie本体で、それ以外はCookieに関する制御をしている。
  • DomainとPathでtwitter.comとそのサブドメインの場合のみCookieを送信できるようにしている。
    • 殆どの場合Path=/。
    • /が少し分かりづらいが、/*という意味。
  • SecureによってHTTPSでないとCookieを送信できない。
  • SameSite=Noneはオリジンをまたいでクッキーを送信して良いこと表している。
    • Noneを指定する場合、Secureが必須。
    • CSRF攻撃の予防のためにSameSiteがあるわけだが、Noneでも大丈夫なのだろうか。

Strict-Transport-Security

strict-transport-security: max-age=631138519

HTTPではなくHTTPSを利用するように促すヘッダ。リダイレクトとは違い、ブラウザが改めてHTTPSとして接続し直す。

利用例はMDN Web docsで示されている例がわかりやすい。HTTPでリクエストが来たとき、HTTPSのリダイレクトが記述されたHTTPレスポンスを返すのは、暗号化されていないため悪意のあるサイトへリダイレクトするよう書き換えられる可能性がある(中間者攻撃)。だからHTTPではなく新しくHTTPSで接続し直してとだけ返信するStrict-Transport-Securityが有用。

x-connection-hash

x-connection-hash HTTP response header

twitterが独自に定義しているヘッダだと思われる。

X-Content-Type-Options

x-content-type-options: nosniff

Content-Typeで指定したMIMEをブラウザが書き換えてはいけないと指定している。MIME Confusion Attackという攻撃を防げる。詳しくは以下のサイトで。

mozsec-jp.hatenablog.jp

X-Frame-Options

x-frame-options: DENY

ページが<frame>や<iframe>、<embed>、<object>の中に表示することを禁止している。クリックジャッキング攻撃を防げる。

X-Powered-By

x-powered-by: Express

一部のソフトウェアで送信されるヘッダーのようで、送信したソフトウェアがExpressであることを表す。

X-Response-Time

x-response-time: 155

以下のサイトによると、リクエストがミドルウェアに来てから、ヘッダが書かれるまでの時間を記録している。twitter以外でも使われていた。

X-Response-Time HTTP response header

X-XSS-Protection

x-xss-protection: 0

XSSを検出しても何もしないことを意味している。CSPで代用でき、レガシーブラウザをサポートしない限りはなくてもよいヘッダーのようだった。

CORS セーフリストレスポンスヘッダー

twitterにあったHTTPヘッダーの中で以下のものはCORS セーフリストレスポンスヘッダーと呼ばれる。

  • Cache-Control
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

CORS(オリジン間リソース共有)によってオリジンをまたいでHTTPクエリがとんでも、これらのヘッダーは含ませてもよいとされる。逆に、SetCookieなどは含ませてはいけない。

最後に

調べてみて、どこまでが実用上必要で、どこまでがレガシーをサポートするためなのかがわかって勉強になった。別のサイトについても調べてみたい。

参考

Cross-Origin-Opener-Policyについて - ASnoKaze blog

キャッシュについて整理 - Qiita

CookieのDomainとPath属性の仕様について調べた話 - emahiro/b.log

HTMLで文字エンコーディングを指定する

【翻訳】Firefox における MIME Confusion Attack の防止 - Mozilla Security Blog 日本語版

HttpFoundationで画像の条件付きGETを実装してみる (Symfony Advent Calendar JP 2012 - Day 22) - k-holyのPHPとか諸々メモ