背景
- HTTPレスポンスに付けるセキュリティ系のヘッダーについて、断片的にしか理解していなかったので改めて調べ直した
- 代表的な5つを中心に、それぞれ何を防いでいるのかを整理する
5つのセキュリティヘッダー
| ヘッダー | 役割 |
|---|
| CSP | 悪意のあるスクリプトを実行させない |
| HSTS | HTTPS通信を強制して盗聴を防ぐ |
| frame-ancestors | 偽サイトに画面を埋め込ませない |
| X-Content-Type-Options: nosniff | ファイルを勝手にプログラムとして解釈させない |
| Referrer-Policy | 閲覧していたURLなどの情報漏れを減らす |
CSP(Content-Security-Policy)
- ページ内でスクリプト・スタイル・画像などを読み込んでよい取得元をホワイトリスト形式で指定するヘッダー
- 主なディレクティブ
| ディレクティブ | 制限対象 |
|---|
script-src | 実行してよいスクリプトの取得元 |
style-src | 適用してよいスタイルの取得元 |
img-src・connect-src・font-src | 画像・fetch通信・フォントの取得元 |
object-src 'none' | Flash等のプラグインを無効化 |
base-uri | <base>タグで指定できるURLを制限 |
script-srcにインラインスクリプトを許可しない設定にしておくと、攻撃者が入力フォームなどからscriptタグを注入できても実行されない、というのがXSS対策としての効果- 既存サイトに導入する場合、いきなり
Content-Security-Policyで強制するとレイアウト崩れを起こしやすいため、違反のみ記録するContent-Security-Policy-Report-Onlyで様子を見てから本番適用するのが定石
HSTS(HTTP Strict Transport Security)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadのように指定- 一度このヘッダーを受け取ったブラウザは、指定期間(
max-age、秒単位)中は該当ドメインへの通信を常にHTTPSに置き換える - 効果があるのは「2回目以降のアクセス」で、初回アクセス時にHTTPで接続されてしまうと保護されない(この弱点を補うのがブラウザベンダー運営のpreloadリスト)
includeSubDomainsを付けるとサブドメインにも適用され、preloadはChromeなどに組み込まれているプリロードリストへの登録希望を示すフラグ
frame-ancestors
- 自分のページを
<iframe>や<frame>、<object>で埋め込んでよい親ページの取得元を指定するCSPのディレクティブ - 古くは
X-Frame-Options(DENY・SAMEORIGIN・ALLOW-FROM)という専用ヘッダーで同様のことをしていたが、複数オリジンを許可できないなど柔軟性に欠けるため、現在はCSPのframe-ancestorsに統合されている - これを設定していないと、自サイトを透明なiframeで覆われて別サイトのボタンだと思わせてクリックさせる「クリックジャッキング」を防げない
X-Content-Type-Options: nosniff
- ブラウザは
Content-Typeが曖昧だったり省略されていたりすると、実際のバイト列を見て種類を推測する「MIMEスニッフィング」という挙動を持つ - この挙動を悪用すると、
Content-Type: text/plainで配信しているはずのファイルが、中身次第でHTMLやJavaScriptとしてブラウザに解釈されてしまうことがある X-Content-Type-Options: nosniffを付けると、このスニッフィングを無効化し、サーバーが宣言したContent-Typeどおりにのみ扱わせられる
Referrer-Policy
- ページ遷移やサブリソース取得の際にブラウザが送る
Refererヘッダー(直前にいたページのURL)の送り方を制御する - 主な値
| 値 | 挙動 |
|---|
no-referrer | 一切送らない |
same-origin | 同一オリジンへの遷移時のみ送る |
strict-origin-when-cross-origin | クロスオリジンへはオリジンのみ送り、HTTPSからHTTPへのダウングレード時は送らない(多くのブラウザの現在のデフォルト) |
Refererにトークン付きのURLやユーザー固有のパスが含まれていると、リンク先の第三者サイトにその情報がそのまま渡ってしまうため、指定しておく意味がある
自分のサイトでの設定状況
実際にm1ke.orgへcurlでアクセスして、レスポンスヘッダーを確認してみた。
1
| curl -s -D - -o /dev/null https://www.m1ke.org/
|
1
2
3
4
| HTTP/2 200
strict-transport-security: max-age=31536000
server: Netlify
...
|
- HSTSはNetlifyがデフォルトで付与しており、既に有効になっていた
- CSP・frame-ancestors・X-Content-Type-Options・Referrer-Policyはいずれも未設定
- Netlifyでは
netlify.tomlに[[headers]]セクションを追加するか、static/_headersファイルを置くことでレスポンスヘッダーをカスタマイズできるので、必要であれば次はそちらを設定する
まとめ
- CSP・HSTS・frame-ancestors・X-Content-Type-Options・Referrer-Policyの5つは、いずれも「ブラウザに対して追加の制約を指示する」という共通点を持つヘッダーで、XSS・盗聴・クリックジャッキング・MIMEスニッフィング・リファラ経由の情報漏れといった、それぞれ異なる攻撃経路に対応している
- 自分のサイトではHSTS以外はまだ未設定だったので、静的サイトであることも踏まえて優先度の高いものから
netlify.tomlで追加を検討したい。