X-Content-Type-Options
使い方
MIME スニッフィングは、ブラウザがレスポンスの内容を検査し、レスポンスボディに見つかったパターンに基づいて宣言された Content-Type を上書きするブラウザの挙動です。設定が誤ったサーバーへの便宜として意図されたものですが、MIME スニッフィングはセキュリティ上の穴を開けます。攻撃者が画像に偽装したファイルをアップロードし、ブラウザがその内容を HTML や JavaScript としてスニッフィングすると、クロスサイトスクリプティング攻撃が実行されてしまいます。
X-Content-Type-Options ヘッダーはこの穴を塞ぎます。nosniff に設定すると、ブラウザは Content-Type ヘッダーに厳密に従い、宣言された型が期待される型と一致しないリソースの読み込みを拒否します。スタイルの宛先では、Content-Type が text/css でない限りブラウザはレスポンスをブロックします。スクリプトの宛先では、Content-Type が有効な JavaScript の MIME タイプでない限りブラウザはレスポンスをブロックします。
このヘッダーは標準的なセキュリティ強化策として広く導入されており、多層防御のために Content-Security-Policy や X-Frame-Options と併せて利用することが推奨されます。
nosniff
nosniff は定義されている唯一の値です。このディレクティブを設定すると、ブラウザが宣言された Content-Type から逸脱してレスポンスを MIME スニッフィングすることを防げます。
例
MIME スニッフィングを無効化して JSON API のレスポンスを配信するサーバーです。ブラウザがレスポンスを厳密に JSON として扱うようにします。
Content-Type: application/json
X-Content-Type-Options: nosniff
正しい Content-Type とスニッフィング防止を伴って配信される CSS ファイルです。ブラウザがファイルを再解釈するのを防ぎます。
Content-Type: text/css
X-Content-Type-Options: nosniff
トラブルシューティング
nosniff によってブロックされたリソースは、宣言された Content-Type とリソースの宛先に期待される型との MIME タイプの不一致を指摘するコンソールエラーを出力します。
MIME タイプの不一致でスクリプトがブロックされる。ブラウザは Refused to execute script from ’…’ because its MIME type (‘text/plain’) is not executable というログを出します。これは、サーバーが JavaScript ファイルを有効な JavaScript の MIME タイプ(text/javascript、application/javascript)以外の Content-Type で送っている場合に発生します。サーバーの設定を修正してください。nginx では http ブロックに include mime.types; があることを確認します。Apache では設定ファイルまたは .htaccess に AddType text/javascript .js があることを確認します。
nosniff と誤った MIME タイプにより CSS が適用されない。コンソールには Refused to apply style from ’…’ because its MIME type (‘text/html’) is not a supported stylesheet MIME type と表示されます。サーバーが CSS ファイルを text/css ではなく text/html や text/plain として送っています。nginx では types { text/css css; } を追加するか、既定の mime.types ファイルを読み込むことで不一致が解消します。Apache ではサーバー設定に AddType text/css .css を追加します。
サーバーが静的ファイルに誤った Content-Type を送る。設定が誤ったサーバー、CDN、オブジェクトストレージ(S3、GCS)は、静的ファイルを application/octet-stream や text/plain として配信することがよくあります。DevTools の Network タブでリクエストを選択してレスポンスヘッダーを確認し、各リソースの Content-Type を調べてください。S3 ではアップロード時に ContentType のメタデータを設定します。CDN から配信されるアセットについては、ほとんどの CDN がオリジンの Content-Type をそのまま通すため、オリジンが正しい型を返していることを確認してください。
DevTools の Console でブロックされたリソースを診断する。Console タブを開き、MIME 関連のエラーでフィルタリングします。ブロックされた各リソースのメッセージには、URL、宣言された MIME タイプ、期待される型が含まれます。Network タブと突き合わせてください。ブロックされたリクエストを選び、Headers パネルを開いて Content-Type レスポンスヘッダーを確認します。修正は常にサーバー側で Content-Type を正すことであり、nosniff ヘッダーを外すことではありません。
設定
すべてのレスポンスに nosniff を適用してください。オーバーヘッドはごくわずかで、保護はスクリプト、スタイル、その他のサブリソースに及びます。
nginx:
add_header X-Content-Type-Options nosniff always;
Apache:
Header always set X-Content-Type-Options nosniff
IIS(web.config):
<code class="language-xml"><customHeaders>
<add name="X-Content-Type-Options"
value="nosniff" />
</customHeaders>