XSS入門:反射型・蓄積型・DOM型と対策
innerHTMLを避ける 安全なDOM API
この回でやること
innerHTMLを避け、textContentやcreateElement、setAttributeで安全に画面を組む使い分けを見ます。テンプレートの自動変換を外す記法の危うさも扱います。
- 読む 約 7 分
- 最後にクイズ 1 問
このレッスンで学ぶこと
安全なDOM APIとは、ブラウザ内のJavaScriptで画面を組むとき、利用者由来の文字をHTMLとして解釈させずに置く組み方です。この回は innerHTML の代わりに何を使うかを見ます。
最後まで読めば、URLの # に <b>test</b> を入れて、直ったかどうかを自分で確かめられるようになります。
innerHTMLは文字列をHTMLとして読む
innerHTML は、渡した文字列をHTMLとして解釈します。だからソースとシンクの回でいう、シンクそのものです。利用者由来の文字をここに入れると、そのままDOM型XSSになります。
JavaScript
box.innerHTML = "おすすめ " + tag;tag が利用者の決められる値なら、タグやスクリプトとして解釈されます。
文字として出すならtextContent
文字を「文字として」見せたいだけなら、textContent を使います。これは渡した文字列をHTMLとして解釈せず、そのまま文字として置きます。
JavaScript
box.textContent = "おすすめ " + tag;tag に <b>test</b> が入っても太字にならず、<b>test</b> という文字が並ぶだけです。DOM型を直す中心はこの置き換えです。要素を組み立てたいときは、createElement で要素を作り、中身は textContent で入れ、属性は setAttribute で付けます。文字列を継ぎ足してHTMLにしないのが要点です。ただし setAttribute で href を付ける場合は、前回のとおりスキームの確認が要ります。
自動変換を外す記法に注意
多くのテンプレートエンジンは、二重の波かっこのような普通の出力を、既定で本文文脈の変換にかけます。ところが「生のHTMLとして出す」記法を使うと、その自動変換が外れます。
製品によって書き方は違いますが、三重の波かっこ、safe の指定、v-html、dangerouslySetInnerHTML などが生HTML出力に当たります。ここに利用者由来の文字を入れると、自動変換をわざわざ外して穴を開けることになります。使うのは自分が組んだ固定のHTMLに限ります。
手を動かす
練習用のショップのDOM型の箇所を innerHTML から textContent に替え、URLの # に <b>test</b> を入れても太字にならず文字で出ることを確かめます。あわせてSourcesで innerHTML・outerHTML・document.write と、テンプレートの生HTML記法を検索し、利用者由来が渡っていないかを見ます。