セキュリティ系レスポンスヘッダーについて書きたくなった
CREATED: 2024 / 04 / 10 Wed
UPDATED: 2024 / 04 / 10 Wed
セキュリティ系レスポンスヘッダー
Referrer-Policy, Strict-Transport-Security, X-Content-Type-Options, X-XSS-Protection, X-Frame-Options, Content-Security-Policy のことを言ってます。 こいつらは Web サイトを構築するときに必ず考慮する要素です。
Referrer-Policy
Referrer というリクエストヘッダーにはアクセスしたページに来る前のページの URI が含まれる。
たとえば、X のポストに記載されているリンクから別のサイトにアクセスすると、その別サイトの Referrer には X の URI が含まれることになる。
で、この URI にはドメインに加えてパスパラメーターやクエリパラメーターも含まれるので、攻撃者が仕掛けた悪意のあるサイトにアクセスしてしまうと Referrer からそれらの情報を抜き取られてしまう恐れがある。
こういう場合に Referrer を参照させないように設定できるのが Referrer-Policy
である。
Referrer-Policy
の設定オプションは MDN web docs のページを見てほしい。
とにかく、Referrer を別ページに飛んだときに参照させたくない場合は no-referrer
で良いし、参照させても良いがオリジンだけの場合は origin
だったり、同一オリジンと別オリジンで挙動分けたい場合は規定値の strict-origin-when-cross-origin
もしくは origin-when-cross-origin
あたりになるのかなと思う。
Strict Transport Security
HTTP Strict Transport Security は略して HSTS と呼ばれる。 このレスポンスヘッダーを受けたページは次回以降、指定された日時までは、強制的に HTTPS でアクセスするようになる。
以下のような構文になっていて max-age
に指定した期間のうちは HTTPS でのアクセスを強制する。
Strict-Transport-Security: max-age=<expire-time>
詳しくはこちらを見てほしいが、サブドメインを含めて HTTPS アクセスに限定させるかのオプション(includeSubDomains)もつけることができる。
しかしながら、このアクセスの強制はレスポンスヘッダーが返ってきた後の話なので、初回のアクセスが HTTP で行われるとリクエスト情報が盗み取られる可能性がある。 これを解決するのが HSTS プリロードである。
HSTS プリロード
HSTS プリロードリストに自サイトを登録しておくと、そのサイトは初回から HTTPS で接続することができるようになる。 登録はこちらから。
リストに載るまでは数ヶ月かかるらしい。
また、ヘッダーの設定としては以下のように preload
を追加する必要がある。
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options
かつて IE は MIMETYPE ではなくファイルの中身からそのファイルの扱い方を判断していたのだが、この挙動を防ぐために作られたのが X-Content-Type-Options
である。
これを許してしまうと、png の拡張子がついていても中に js のスクリプトが書かれているファイルならそれは js ファイルであると判断され、ブラウザで実行されてしまう可能性がある。
徳丸さんのライブ配信では、画像のアップロード機能がある Web サービスなどで、表向きは png でも中身が html となっているファイルがアップロードされてしまうと、ブラウザはそれを html と解釈してしまい、結果的に XSS に繋がってしまう、という話が紹介されていました。
現在は X-Content-Type-Options: nosniff
を指定してあげればこのブラウザによる挙動を抑止できるようになっている。
で、発端となったのは IE の挙動ではあったのだが、現在の主要なモダンブラウザでもこの挙動は受け継がれているため、X-Content-Type-Options
は今でも考慮すべき設定である。
X-Frame-Options
X-Frame-Option
はクリックジャッキング攻撃(参考)を防止することができる機能である。
クリックジャッキングとは iframe
を利用して罠サイト上のコンテンツの前面に CSS で透過して隠した攻撃対象のサイトを仕込み、ユーザー自身の手で意図しない操作へ誘導する攻撃方法である。
たとえば、「アンケートに答えると豪華賞品プレゼント!」みたいな罠サイトの文言の上にユーザーがログインしている攻撃対象のページを透過表示させ、「応募する」ボタンの上にちょうど攻撃対象ページの「アカウント削除」ボタンがくるように位置調整をすることで、ユーザーの知らないうちに自分の手でアカウントを削除させると言ったことができてしまう。
これを防ぐにはそもそも攻撃対象サイトを別サイトの iframe で表示させられないようにしてあげればよい。
X-Frame-Options
では別サイトでの iframe による表示の可否を設定することができる。
X-Frame-Options
には ORIGIN
と DENY
のどちらかを設定することができる。
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
DENY
は完全に別サイトでの表示を禁止させるので、特に理由がなければ脳死でこれを選ぶ。
SAMEORIGIN
は同一オリジン内では iframe
表示を許可する。
X-XSS-Protection
X-XSS-Protection
の設定は、字面だけ見ると何だか必要そうにも思えるが、正直なところ無効にして良い。
MDN web docs にも書いてあるが、このヘッダーは非標準であり、目的とは反対に脆弱性を生み出す可能性も孕んでいるので、基本的には無効にして良い。
X-XSS-Protection: 0
X-XSS-Protection
は XSS の脆弱性を検知するとそのページを部分的に書き換える挙動を取るため、ページが正常に機能しなくなる恐れもある。
そのため、有効にするにしても X-XSS-Protection: 1; mode=block
で根本的にレンダリングを停止させる方法をとった方が良い。
徳丸さんが紹介してたこのページも参考になった。
が、それでもやっぱりこれは無効化して Content Security Policy を設定する方が良いと思う。
Content Security Policy
Content Security Policy(CSP) を設定してあげると、実行すべきスクリプトやアクセスできる URI などを制限することができる。 これにより第三者に埋め込まれたスクリプトや、第三者が仕込んだ URI へのリクエストが実行されないようにすることができる。
例えば以下の CSP は自サイトのドメインからのみリソースを取得するように制限される。
Content-Security-Policy: default-src 'self'
CSP のディレクティブはこちらに一通り記載されているが、js, css, iframe などのコンテンツの制限を設定することができるようになっている。
また、動的にクライアントへ返却する nonce をスクリプトに埋め込むことで、同一の nonce
を持たないスクリプトの実行を制御することができる。
nonce
の埋め込みは必須ではないが、スクリプトが仕込まれるような状況が考えられるのであれば設定しておいた方が良い。
モダンなフレームワークやライブラリを使っているだけで裏でよしなにやってくれることもありますが、XSS の対策には CSP を常に念頭に置いておいた方が良いかと思います。
Cookie 規制について
今年から google が cookie 規制に動き始めていて、サードパーティー cookie は chrome でも廃止されることになっている。 Firefox や Safari ではすでに廃止されていて、とうとう chrome もということになり、広告界隈の方面でどうやら騒ぎになっている話のようですが、セキュリティの側面から言えばこれはどちらかというと良い話である。
サイトに埋め込まれた広告のタグの中でサーバーパーティー cookie が生成されると、これがユーザーのインターネット上の行動を監視して、画面上の広告の表示を動的に切り替えるのだが、これはユーザーのエクスペリエンス的にはあまりよろしくない、というか個人的に非常に好ましくない。 こういうのが淘汰されてセキュリティが高まるのであれば尚更良いことである。
参考
サードパーティクッキーとは?廃止の影響と3つの対応策を解説 【2023年版】Cookie規制とは?日本の状況・影響・対策方法まで解説 Cookie規制とは?デジタルマーケティングへの影響と今後の対策を考える
を仕舞い
動機になった徳丸さんのライブ配信はこちら👇 https://www.youtube.com/watch?v=NRaU_dRvncQ&t=2828s