セキュリティ対策のための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 を防御できます。
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>
ディレクティブ一覧は下記を参照してください。
このように、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 対策をしてくれるので、使用する必要はありません。
X-Frame-Options
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
ブラウザがそのページを <iframe>
・<frame>
・<object>
などの中に表示することを許可するかどうかを制御することで、クリックジャッキング攻撃を防ぎます。
これも非推奨になり、より柔軟な制御ができる Content-Security-Policy のframe-ancestors
の使用が推奨されます。
その他の参考文献
Discussion