CORS問題でAJAXリクエストが失敗する場合の対策として、CORSを設定を紹介しているところまでは良いのですが、他のオプションとしてJSONPを挙げているページを見つけました。記事作成が2018年4月になっていたのでつい最近のことです。あまり知られていないようです。
誤解の無いよう正確に書いておきます。誰かに見られて困るデータが含まれる場合、JSONPは禁止です。
JSONP
JSONP (JSON with padding) とは、scriptタグを使用してクロスドメインな(異なるドメインに存在する)データを取得する仕組みのことである。HTMLのscriptタグ、JavaScript(関数)、JSONを組み合わせて実現される。
https://ja.wikipedia.org/wiki/JSONP
XHRだとサイト間をまたいでデータ共有できない制限を回避する為に利用されてきた仕組みです。
<script type='text/javascript' src='http://another.domain.example.com/getjson?callback=parseResponse'>
このような感じでコールバックを指定して使います。
何がどう危険なのか? – JSONPインジェクション
簡単に説明すると、<script>タグでJSONを呼び出すとコールバック関数を使ってJSONデータを処理します。このコールバック関数を攻撃にすることにより、攻撃者は情報を不正に取得できます。
詳しくはJSONPインジェクションを紹介しているページ(英語)を参照してください。
次の画像はこのサイトで紹介している攻撃用ページの例です。罠サイトから”とても安全な銀行”(verrysecureback.ro)に対して攻撃を仕掛けるサンプルコードです。
上記のサイトに記載されていますが、コールバックを隠していても簡単な物だと総当たり攻撃で判ってしまいます。
どうするのか?
JSONPをすべて禁止し、CORS設定(Access-Control-Allow-Origin)を利用し、全てXHRでリクエストします。
CORSの仕様:https://www.w3.org/TR/cors/
※ 公開情報で誰に何を見られても良いモノなら、JSONPでも問題ありません。とは言ってもこの場合もCORSで公開した方が親切だと思います。
※ 認証済みユーザーのみにアクセスを許可している場合などに問題になります。JSONPだと誰でも(どのサイトから、罠サイトでも)アクセスできます。この場合でも、CSRF対策の要領で真正性を保証すれば安全性を保証できます。
X-Content-Type-Options: nosniff
少し唐突感がありますが、nosniffオプションの話です。JSONPは<script>タグでJSONを読込みます。この<script>タグでJSONを読み込む、という動作にはJSONをJavaScriptとして読み込むリスクがあります。
2017年初め頃、Firefoxに「X-Content-Type-Option: nosniff」サポートが追加されました。
nosniff
Blocks a request if the requested type is“
style
” and the MIME type is not “text/css
“, or
“script
” and the MIME type is not a JavaScript MIME type.
このオプションにより
- CSSのメディアタイプを厳格に扱う(ブロックする)
- JavaScriptのメディアタイプを厳格に扱う(ブロックする)
ようになりました。この時、Chromeは既にX-Content-Type-Options: nosniffをサポートしていました。
X-Content-Type-Options: nosniffが追加された理由
紹介したページに記載しているので詳しくはそちらを参照してください。JSONPはオブソリートなので使用禁止です。
JSONPはJSONPインジェクションと呼ばれる攻撃に脆弱だからです。JSONをJavaScriptとして読み込むことが危険だからです。
これに対応する為に昨年FirefoxにX-Content-Type-Options: nosniffが追加されました。これを設定すると
Content-Type: application/json
の場合、Firefox/Chrome/Edge/IEはJavaScriptとして実行しなくなります。
折角CORSでアクセス可能なドメインを制限しても、<script>タグで読み込めてしまうようではたとえ内容が分らなくても問題の原因になり得ます。
nosniffはIE専用では?と思った方も居るかも知れません。IE専用でした。しかし、今は標準となるべく作業中のようです。
勝手に違うメディアタイプとして解釈される動作は問題になる可能性があるので、常にnosniffを付ける方が良いでしょう。
※ JSONはプログラムではなく、データなのでnosniffを付けると手違いがあっても何らかのコードを実行できなくなります。
※ 本来JSONはプログラムとして実行できない物です。しかし、nosniffが無いとJSONデータを出力する際にエスケープ漏れなどがあり、JavaScriptコードを挿入可能な場合、JavaScriptが実行されてしまいます。JSON、CORSの効果も半減と言えます。