XSS は「どこで悪意あるスクリプトが混入するか」で 3 つに分類される。
分類
- 反射型 — リクエストに含まれた文字列がそのまま応答に埋め込まれる
- 格納型 — DB に保存された投稿などが他ユーザのページに描画される
- DOM-based — サーバは関与せず、クライアント側 JS が
location.hashなどを不用意に DOM へ挿入する
対策の基本
- 出力時に文脈へ合わせてエスケープする(HTML / 属性 / JS / URL で方法が違う)
innerHTMLではなくtextContentを使う- Content-Security-Policy で多層防御する
Content-Security-Policy: default-src 'self'; script-src 'self'
フレームワークでも油断できない箇所
React でも次のような書き方は素通しになる。
// 危険: サニタイズなしで挿入される
<div dangerouslySetInnerHTML={{ __html: userInput }} />
エスケープは「入力時」ではなく「出力時」。保存データはあくまで生のまま持ち、描画する文脈で処理するのが原則。
Naxii の置き場