XSS入門:反射型・蓄積型・DOM型と対策
XSS対策 出力時のエスケープ
この回でやること
XSS対策の出力エスケープを扱います。入力時に文字を取り除くのではなく、出力時に文脈へ合わせて変換することが軸だと組み直します。
- 読む 約 7 分
- 最後にクイズ 1 問
このレッスンで学ぶこと
出力時のエスケープは、利用者の文字を出力するその瞬間に、出力先の文脈へ合わせて変換することを指します。この回は、本文と属性で守る文字が違うという前2回の話を、対策の側から組み直します。
読み終えるころには、レビューに 1 < 2 と書いて、守れているかどうかを画面で判定できるようになります。
なぜ入力時に取り除いてはいけないのか
入力を受け取った時点で危ない文字を取り除く方式には、原理的な弱さがあります。理由は次のとおりです。
- 同じ文字列が、本文に出るか属性に出るかで必要な変換が違う。入力の時点では、その文字がどこに出るかまだ決まっていない
- 取り除くと、正規の入力が壊れる。レビューに
価格 < 3000と書けず、名前の記号も消える。SQLインジェクション編の再検証で見た、正規利用を締め出す罠と同じ形
保存や受け取りの段では、利用者の文字はそのまま持っておきます。壊すのは、出さないときではなく出すときに限ります。
出力する場所で変換を選ぶ
エスケープは、出す場所が分かって初めて正しく選べます。文脈ごとの対応は次のとおりです。
- HTMLの本文へ出すなら、小なり記号・大なり記号・アンパサンドを実体参照へ変換する
- 引用符で囲んだ属性値へ出すなら、囲みと同じ引用符を変換する。
hrefやsrcはhttpとhttpsだけを通す <script>の中やJSの文字列へ利用者由来を入れるのは避ける
同じ「田中さんの <b>」という入力でも、本文なら不等号を変換し、属性なら引用符を変換します。出力先が決まってはじめて、どれを変換すべきかが決まります。
すでに変換した文字をもう一度変換すると、&lt; のように壊れ、画面に < という文字がそのまま出ます。二重変換を避けるため、変換は表示の直前の1箇所だけで行い、保存済みの値を変換して保存し直さないようにします。
手を動かす
練習用のショップのレビューに 1 < 2 と書いて保存し、画面で 1 < 2 と正しく読めるかを見ます。同時に <b>test</b> が太字にならず文字で出るかを見ます。両方が成り立てば、入力を取り除かずに出力時の変換で守れている状態です。片方だけなら、変換の取りこぼしか二重変換を疑います。