• 診断項目 No.120/127
  • セキュリティヘッダー
  • 重大度 中(medium)

nosniffを全応答へ適用とは?X-Content-Type-Optionsの仕組み・設定方法・診断基準

nosniffを全応答へ適用とは、HTMLだけでなくCSS・JavaScript・画像・404応答にもX-Content-Type-Options: nosniffを付けることです。全応答が必要な理由、always指定の必要性、付いているかの確認方法を示します。

結論(nosniffを全応答へ適用)

nosniffを全応答へ適用とは、X-Content-Type-Options: nosniffヘッダーを、トップページだけでなく下層ページ・API・ダウンロードファイル・エラー応答を含むすべてのHTTP応答に付けることです。nosniffはブラウザに内容からの種類の推測(MIMEスニッフィング)をやめさせ、宣言されたContent-Typeに従わせます。OWASP ASVS 5.0.0 V3.4.4が全応答への付与を求めており、Webサーバーの共通設定で一括付与するのが基本です。

この記事のポイント

  • MIMEスニッフィングがあると、アップロードされた画像やテキストがスクリプトやスタイルシートとして解釈される余地が生まれます。
  • nosniffが有効なとき、Content-Typeが正しくないスクリプト系とスタイルの読み込みがブロックされます。画像は対象外です。
  • 攻撃に使われるのはHTMLよりアップロードファイル・JSON・CSV・エラーページなので、トップページだけでは効果がありません。
  • セキュリティAIチェッカーはトップと下層最大2ページの応答を調べ、1つでもnosniffがなければ×と判定します。対象外はありません。
  • 導入前に、.jsと.cssが正しいContent-Typeで配信されているかを確認すれば、サイトを壊さずに付与できます。
診断項目名nosniffを全応答へ適用
項目IDcrawl.nosniff-coverage
分類セキュリティヘッダー
重大度・配点の重み中(medium) 重み 3
関連する標準・ガイドラインOWASP ASVS 5.0.0 V3.4.4(すべてのHTTP応答に X-Content-Type-Options: nosniff を含める、L2)、WHATWG Fetch Standard 3.6(X-Content-Type-Options ヘッダーと「nosniff によるブロック」)、OWASP WSTG-CONF-14(Other HTTP Security Header Misconfigurations)、OWASP HTTP Headers Cheat Sheet、CWE-693(Protection Mechanism Failure)

nosniffを全応答へ適用とは

nosniffを全応答へ適用とは、X-Content-Type-Options: nosniff レスポンスヘッダーを、トップページだけでなく、下層ページ・API・ダウンロードファイル・エラー応答を含むすべてのHTTP応答に付けることです。

ブラウザには、サーバーが示した Content-Type と実際の内容が食い違うときに、内容を見て種類を推測する「MIMEスニッフィング」という挙動があります。便利な反面、利用者がアップロードした画像やテキストファイルが、スクリプトやスタイルシートとして解釈される余地を生みます。X-Content-Type-Options: nosniff は、この推測をやめ、宣言された Content-Type に従うようブラウザへ指示するヘッダーです。

セキュリティAIチェッカーのこの項目は、トップページと巡回した下層ページのすべての応答に nosniff が付いているかを確認します。OWASP ASVS 5.0.0 V3.4.4 は「すべてのHTTP応答」への付与を求めています。トップページ単体での判定は「MIMEスニッフィング対策」、Content-Type 自体の明示は「Content-Typeと文字コードを全テキスト応答へ明示」で評価し、このページは nosniff を全応答に漏れなく付けることに絞って解説します。

nosniffはどう働くのか(Fetch Standard)

ブラウザの判定手順

Fetch Standard では、次の手順で nosniff を判定します。

  1. X-Content-Type-Options ヘッダーの値を取得し、カンマで分割する。
  2. 分割した最初の値が、大文字小文字を区別せず nosniff に一致すれば「nosniff 有効」とする。

nosniff が有効なとき、次の読み込みはブロックされます。

読み込み先(destination)ブロック条件
スクリプト系(script、worker、sharedworker、serviceworker、audioworklet、paintworklet)Content-Type がない、またはJavaScriptのMIMEタイプでない
スタイル(style)Content-Type がない、または本質部分が text/css でない

仕様は、攻撃に関係するのはスクリプト系とスタイルであるためこの2種類に限定し、画像は既存コンテンツとの互換性がないため対象外にしたと説明しています。ASVS 5.0.0 は、このヘッダーがブラウザのクロスオリジン読み取りブロック機能(CORB)を働かせる点にも触れています。

値の書き方

  • 有効な値は nosniff だけです。
  • WebサーバーとCMSの両方が付与して X-Content-Type-Options: nosniff, nosniff となった場合も、最初の値が nosniff なので有効です。
  • nosnif などの綴り誤りや、nosniff 以外の値は無効です。

なぜ「全応答」なのか

攻撃に使われるのは、HTMLページよりも、アップロードされたファイル、JSONを返すAPI、CSV・テキストのダウンロード、エラーページなどです。トップページだけに付けても、こうした応答に付いていなければ効果がありません。Webサーバーの共通設定で、ステータスコードや種類を問わず全応答に付与するのが基本です。

nosniffについてよくある誤解

  • 「Content-Type を正しく設定していれば不要」:正しく設定していても、付け忘れや誤設定が1か所でもあると推測が働きます。nosniff は誤設定時の安全網です。
  • 「nosniff を付けると画像が表示されなくなる」:仕様上、画像はブロック対象ではありません。影響が出るのは、誤った Content-Type で配信しているスクリプトとCSSです。

nosniffを全応答へ適用の診断基準(セキュリティAIチェッカー)

取得対象

  • トップページ(最終応答)と、巡回で発見した同一オリジンの下層ページのうち最大2ページ(GET、リダイレクト最大2回、応答上限180KB、タイムアウト5秒)。取得に失敗したページは対象外です。
  • HTML・HTTP/HTTPSを問わず、取得できたすべての応答を評価します。

「nosniff あり」とする条件

X-Content-Type-Options ヘッダーの値をカンマで分割し、最初の値の前後の空白を除いて小文字化したものが nosniff であること。Fetch Standard の判定手順と同じです。

判定条件

判定条件得点係数
○ 問題なし(pass)評価したすべての応答で nosniff あり1
× 要改善(fail)評価した応答のうち1つでも nosniff なし0

トップページは常に評価対象になるため、この項目に対象外(na)はありません。重み3のため、× の場合は3点分を失います。根拠欄に「何ページ中何ページで不足か」を表示します。

判定の限界

  • 評価するのは最大3つの応答(主にHTMLページ)で、画像・CSS・JavaScript・ダウンロードファイルの応答は対象外です。○ でも、別の仕組みで配信される静的ファイルやAPIに付いているとは限りません。
  • 応答上限を超える大きな下層ページは取得に失敗し、評価対象から外れます。

自治体サイトでの判定例

構成判定
.htaccess で Header always set X-Content-Type-Options "nosniff"○
トップページはCMSのPHPが header() で付与しているが、静的HTMLで配信される下層ページには付いていない×
ロードバランサーとWebサーバーの両方で付与して nosniff, nosniff○(付与箇所の一本化は推奨)

nosniffが一部の応答にないとどんなリスクがあるか

  • アップロードファイル経由のXSS:画像やテキストとしてアップロードされたファイルの中身がJavaScriptやHTMLで、配信時の Content-Type が不正確・欠落していると、ブラウザの推測で実行可能な形式として扱われる場合があります。特に旧 Internet Explorer の積極的なスニッフィングはこの種の攻撃に繰り返し悪用されました。
  • スクリプトとしての読み込み:攻撃者が自サイトのページに <script src="https://www.example.lg.jp/upload/xxx.txt"> を書いた場合、nosniff がなく Content-Type が適切でないと、ブラウザがスクリプトとして実行を試みる余地があります。nosniff があれば text/plain の応答はスクリプトとして実行されません。
  • 情報の読み取り:JSONやCSVの応答がスクリプトとして読み込まれると、内容の一部が別サイトから推測される攻撃(クロスオリジンの情報漏えい)の足掛かりになり得ます。nosniff はブラウザのクロスオリジン読み取りブロックを補強します。
  • 自治体サイトで想定される場面:電子申請の添付ファイル、イベント申込のCSV出力、問い合わせフォームの添付など、利用者由来のファイルを同一ドメインで配信する機能があると影響が大きくなります。

nosniffを全応答へ適用する設定方法(Apache・nginx・IIS・Next.js)

Apache(.htaccess または httpd.conf)

<IfModule mod_headers.c>
  # always:404・500・リダイレクトなどのエラー応答にも付与
  Header always set X-Content-Type-Options "nosniff"
</IfModule>

set は同じ種類の既存ヘッダーを置き換えます。ただし Apache は always 付きと既定(onsuccess)とで別の表にヘッダーを保持するため、アプリケーション側(mod_php など)で付与したヘッダーが既定の表にあると、Header always set では置き換わらず二重になることがあります(CGI や mod_proxy_fcgi 経由のヘッダーは always の表に入ります)。二重になっても最初の値が nosniff なら有効ですが、付与箇所の一本化を推奨します。

nginx

add_header X-Content-Type-Options "nosniff" always;

location 内に別の add_header があると、上位の add_header は継承されません。共通ヘッダーをファイルにまとめて include で各所に読み込みます。nginx 1.29.3 以降は add_header_inherit merge; で上位の設定を引き継げます。

IIS(web.config)

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <remove name="X-Content-Type-Options" />
      <add name="X-Content-Type-Options" value="nosniff" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Next.js(Vercel)

// next.config.js
module.exports = {
  async headers() {
    return [{
      source: "/:path*",
      headers: [{ key: "X-Content-Type-Options", value: "nosniff" }],
    }];
  },
};

導入前に確認すること(サイトを壊さないために)

nosniff を付けると、Content-Type が誤っているJavaScriptとCSSが読み込まれなくなります。次を事前に確認します。

  1. .js が text/javascript(または application/javascript)、.css が text/css で配信されているか。
  2. 古いCGIやPHPが動的に生成するスクリプト・CSSが text/html で返っていないか。
  3. JSONP 等で text/plain のままスクリプトとして読み込んでいる箇所がないか。

Apache で拡張子と MIME タイプの対応が欠けている場合は追加します。

AddType text/javascript .js .mjs
AddType text/css .css

付与後は、ブラウザの開発者ツールのコンソールで「MIME type ... is not executable, and strict MIME type checking is enabled」のようなエラーが出ていないか、主要ページを確認します。

全応答に付いているかの確認方法

for u in / /kurashi/ /js/common.js /css/style.css /no-such-page; do
  printf "%s " "$u"
  curl -s -o /dev/null -D - "https://www.example.lg.jp$u" | grep -i '^x-content-type-options' || echo "(なし)"
done

HTMLだけでなく、JavaScript・CSS・アップロードファイル・404応答にも付いていることを確認します。

運用上の注意点(ガードレール)

  • 付与は Webサーバー共通設定の1か所で行い、アプリ側の付与は残していても問題ありませんが、値が nosniff 以外にならないようにします。
  • ファイルアップロード機能がある場合は、nosniff に加え、Content-Disposition: attachment での配信や、別ドメインからの配信を併用すると安全性が高まります。

よくある質問(FAQ)

X-Content-Type-Options: nosniffを付けると画像が表示されなくなりますか?

なりません。Fetch Standardでは画像はブロック対象外です。影響が出るのは、誤ったContent-Typeで配信しているスクリプトとCSSです。

Content-Typeを正しく設定していればnosniffは不要ですか?

不要ではありません。正しく設定していても、付け忘れや誤設定が1か所でもあると推測が働きます。nosniffは誤設定時の安全網です。

nosniff, nosniffと二重に付いていますが有効ですか?

有効です。Fetch Standardはカンマで分割した最初の値がnosniffかどうかで判定するため、WebサーバーとCMSの両方で付与した場合も有効に働きます。ただし付与箇所の一本化を推奨します。

トップページだけに付けても意味がありませんか?

効果は限定的です。攻撃に使われるのはアップロードされたファイル、JSONを返すAPI、CSV・テキストのダウンロード、エラーページなどです。ステータスコードや種類を問わず全応答に付与してください。

付与後に「MIME type is not executable」というエラーが出ました。どうすればよいですか?

スクリプトが誤ったContent-Typeで配信されています。.jsをtext/javascript、.cssをtext/cssで配信するよう、ApacheならAddTypeなどで対応付けを追加します。動的に生成するスクリプトやCSSがtext/htmlで返っていないかも確認します。

nosniffを全応答へ適用の診断で○なら、CSSやJavaScriptにも付いていると考えてよいですか?

そうとは限りません。評価するのは最大3つの応答(主にHTMLページ)で、画像・CSS・JavaScript・ダウンロードファイルは対象外です。curlなどで静的ファイルやAPIにも付いているかを確認してください。

セキュリティAIチェッカーを利用する

この項目を含む127項目を、URLを入れるだけで無料診断します。

参考資料