X-Content-Type-Options: nosniff が効く条件と簡単な確認
軽いメモ程度です
X-Content-Type-Options: nosniff とは
MDNによる X-Content-Type-Options: nosniff の説明は日本語ページでは以下のようになっています。
X-Content-Type-Options は HTTP のレスポンスヘッダーで、 Content-Type ヘッダーで示された MIME タイプを変更せずに従うべきであることを示すために、サーバーによって使用されるマーカーです。
それは、スクリプト等を読み込むHTML側のレスポンスヘッダなのか、スクリプト自身のレスポンスヘッダなのか、検索して出てきた情報だけではわかりにくいなと思ってまとめておきます。
結論
結論としては、スクリプト・スタイル等の本体側にこのヘッダがついている場合にこのヘッダは働きます。
また、追加でわかったこととしては、そもそも <script src="foo.js" />
のように読み込んでおきながら、Content-Type が image/jpeg
のようなものだったら弾くようで、少なくとも私が確認できたのは text/html
のときにブロックするか否かを返すもので、いわば、 X-Content-Type-Options: nosniff
をつけることで、 Content-Type もちゃんと設定してますよ〜と意思表示する、みたいなものと捉えられそうです。
image/jpeg
を nosniff なしでブロックするのは特に Living Standard には記述がないような気がするんですが、私が見つけれていないだけかもしれないので、Chromeの独自仕様なのかどうかはわかりません。
Firefoxも同様の挙動でしたが、そのエラー文の [Learn More]
を押すと上記のページが出てきており、 top-level なドキュメントに対しては自動でMIME sniffingをしないようにする、と書かれています。
規格
一応、規格上は https://fetch.spec.whatwg.org/#x-content-type-options-header に記述されております。
今読み返すとわかるような気もするのですが、以下で一応実験しています。
実験
以下のTypeScriptファイルを用意して、
import express from 'express';
const app = express();
app.get('/', function (req, res) {
// こちらにつけてもつけなくても、スクリプト等の読み込みブロックには関係ない
// res.header('X-Content-Type-Options', 'nosniff');
res.send(`<!DOCTYPE html>
<html>
<body>
hello!
<div id="main"></div>
<script src="/foo.js"></script>
</body>
</html>
`);
});
app.get('/foo.js', function (req, res) {
// ある場合は、(Content-Typeがなければデフォルトで text/html 扱い、以下のように明示しても同じ)になるが、JSのMIMEではないので弾かれる
res.header('Content-Type', 'text/html');
// これがあるかないかで結果が変わる
res.header('X-Content-Type-Options', 'nosniff');
// 逆にこれだけを入れても勝手にブロックされる?独自仕様?
// res.header('Content-Type', 'image/jpeg');
res.send(`
console.log('foo');
`);
});
const port = 3333;
console.log(`Server listening on http://localhost:${port}`);
app.listen(port);
a.ts
で保存してるなら、以下のような感じでやれば起動できまして、
npm init -y
bun i express@4.18.2
# bun i -D @types/express @types/node
bun run ./a.ts
あとはブラウザで https://localhost:3333
を開いて、スクリプトがnosniffが要因でブロックされていることが確認できます。
expressはこういうとき便利だなって思います。
その他の場合
↓ Content-Type: image/jpeg
+ nosniffはなし
↓ Content-Type: image/jpeg
+ nosniffはなし (Firefox)
バージョン情報
- Chrome: Version 120.0.6099.109 (Official Build) (arm64)
- Firefox: 120.0.1 (20231129155202)
世界のラストワンマイルを最適化する、OPTIMINDのテックブログです。「どの車両が、どの訪問先を、どの順に、どういうルートで回ると最適か」というラストワンマイルの配車最適化サービス、Loogiaを展開しています。recruit.optimind.tech/
Discussion