🔒

セキュリティ対策のためのHTTPレスポンスヘッダー

に公開

はじめに

開発インターンの際にセキュリティ対策(主に XSS 対策)として実際に何をすればいいのかわからず、調査をしていったところ、適切な HTTP レスポンスヘッダーを含めるということが挙げられていました。今回は、それぞれのヘッダーについての説明をしていきます。

追加するレスポンスヘッダーの説明

以下に記載するヘッダはセキュリティヘッダとも呼ばれます。これらをレスポンスヘッダに追加することで、ブラウザに対し特定の動きを制限するように指示できます。セキュリティヘッダには RFC で規格化されているものもあれば、X-****のように実際に使用されるが非標準のヘッダもあります。

X-Content-Type-Options

X-Content-Type-Options: nosniff

ブラウザは MIME スニッフィングという手法でコンテンツの形式(Content-Type)を推定しようとします。nosniffにすることでこの推定を許可しないことをブラウザに伝達します。

これにより、以下のような XSS 攻撃の対策になります。

ユーザーが画像をアップロードする機能を使用する際、悪意のある JavaScript が仕込まれた HTML を画像としてアップロードするとしましょう。これは「画像(実は JavaScript を含んだ 画像」で、この画像への URL にアクセスすると、悪意ある JavaScript がそのサイトの JavaScript として実行されます。
スニッフィングを禁止すれば、きちんと画像と解釈してくれるため、XSS を防御できます。

https://www.m3tech.blog/entry/2023/06/13/110000#少し調査が必要なセキュリティヘッダ

Content-Security-Policy (CSP)

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data:;
  frame-ancestors 'none';

web ページに、読み込み可能なコンテンツの種類と出所を制限するポリシーを設定するレスポンスヘッダーです。以下のようなディレクティブを使用することで設定できます。

ディレクティブ 内容
default-src デフォルトの読み込み元 'self'(同一オリジンのみ許可)
script-src JavaScript の読み込み元 'self'
style-src CSS の読み込み元 'self', 'ussafe-inline'(インラインスタイルを許可)
img-src 画像の読み込み元 'self' https://image.example.com/
frame-ancestors 埋め込み(<iframe>タグなど)を許可する親ドメイン 'self'

基本的に default-src を self にしておけば全ての読み込み元が同一オリジンにできますが、画像など別ドメインに置いてある場合は``img-src: 'self' https://image.example.com/ のように上書きする必要があります。

ここで注意しなければいけないのが、script-src をunsafe-inlineにしてインラインスクリプトを許可するともろに XSS 脆弱性が現れます。これを回避するためにサーバーが生成するランダム文字列であるnonceという値を指定することで、同じ nonce を持つ script タグのみが実行できるようになります。

例:

# nonceを設定
Content-Security-Policy: script-src 'nonce-abc123xyz';
# nonce値が一致するので実行される
<script nonce="abc123xyz">
  console.log("このスクリプトは実行されます");
</script>

# nonceがないのでブロックされる
<script>
  alert("これは nonce がないのでブロックされます");
</script>

ディレクティブ一覧は下記を参照してください。
https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Headers/Content-Security-Policy

このように、CSP ヘッダーの default-src を考えなしに設定することですでに使用している外部リソースが全てブロックされてしまう強力な設定なので、きちんと調査をして導入する必要があります。

Strict-Transport-Security

Strict-Transport-Security: max-age=31536000; includeSubDomains

HTTP Strict Transport Security(HSTS)というヘッダで、設定したドメインに HTTP でアクセスしようとしても、HTTPS に飛ばすようにブラウザに指示するセキュリティヘッダです。max-ageは有効期間(31536000 秒= 1 年間), includeSubDomainsはそのドメインだけでなく全てのサブドメインにも HTTPS を強制するための設定です。
また、preloadオプションをつけることで、ブラウザにあらかじめ HTTPS しか使用しないように強制できます。これはHSTS Preload List Submission(Google が管理するリスト)で登録できます。

これにより、中間者攻撃による通信の傍受や、改ざんによって意図しないサイトへリダイレクトされるリスクを減らせます。

Referrer-Policy

Referrer-Policy: strict-origin-when-cross-origin

ブラウザがリンク先に「どの程度の Referer を送信するか」を制御するセキュリティヘッダーです。Referer とは「あるページから別のページに遷移したとき、リンク元の URL 情報」のことです。
strict-origin-when-cross-originにすることで同一オリジンへのリクエストの場合は全文の URL を送信し、異なるオリジンへのリクエストの場合は

  • HTTPS→HTTPS:オリジンだけ送る
  • HTTPS→HTTP:referer を一切送らない
    という送信方法に制限されます。これにより、悪意ある URL へのリクエスト時に参照元 URL 内のクエリなどに含まれる機密情報の漏洩を防止します。

非推奨となったレスポンスヘッダー

X-XSS-Protection

X-XSS-Protection: 1; mode=block

ブラウザが反射型 XSS 攻撃を受けてしまったときに、ページの読み込みを停止するようにブラウザに指示するヘッダ。このヘッダは最新のブラウザではサポートしておらず、前述した CSP ヘッダが反射型以外の全ての XSS 対策をしてくれるので、使用する必要はありません。

https://www.secure-iv.co.jp/techblog/7498

X-Frame-Options

X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN

ブラウザがそのページを <iframe><frame><object> などの中に表示することを許可するかどうかを制御することで、クリックジャッキング攻撃を防ぎます。
これも非推奨になり、より柔軟な制御ができる Content-Security-Policy のframe-ancestorsの使用が推奨されます。
https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Headers/X-Frame-Options

その他の参考文献

https://qiita.com/rihitooooo/items/d1d0a514028da71f59eb
https://www.m3tech.blog/entry/2023/06/13/110000#少し調査が必要なセキュリティヘッダ

Discussion