innerHTMLを安全に扱うためのsetHTMLメソッド
Element#innerHTMLは、文字列をHTMLとして解釈してDOMに反映するプロパティで、ユーザー入力などをそのまま反映させるとクロスサイトスクリプティング(XSS)攻撃のリスクがある。テキストノードであればNode#textContentのように安全に反映できるプロパティができたが、いまだにHTMLとしてそのまま使いたいユースケースもある。
そこでFirefoxが先行してElement#setHTML()という安全に文字列をDOMに反映するための新しいメソッドを実装した。
setHTMLUnsafe()とsetHTML()の違い
setHTML()に似たようなメソッドで、全主要ブラウザで利用できるElement#setHTMLUnsafe()というメソッドがある。
setHTMLUnsafe()は、ほぼElement#innerHTMLと同じで文字列をそのままDOMに反映するため、依然としてXXS攻撃のリスクがある。一方、setHTML()は、文字列を無害化してからDOMに反映するため、XXS対策ができる。
const xxs = "<a href='javascript:alert(\"XSS!!\");'>クリックしてください。</a>"
const safeLink = "<a href='https://example.com'>クリックしてください。</a>"
// <a href='javascript:alert("XSS!!");'>クリックしてください。</a>
unsafeElement.setHTMLUnsafe(xxs)
// クリックしてください。
safeElement.setHTML(xxs)
// <a href='https://example.com'>クリックしてください。</a>
safeElement.setHTML(safeLink)
デモ
以下のテキストをコピーして、入力欄に貼り付けてください。
<!-- XXS -->
<a href="javascript:alert('XSS!!');">クリックしてください。</a>
<!-- Safe -->
<a href="https://example.com">クリックしてください。</a>
innerHTMLの場合
inputに入力されたタグがそのままDOMに反映される。
textContentの場合
inputに入力されたタグがテキストとして表示されるので、<a href="...">クリックしてください</a>のように表示される。
setHTMLUnsafeの場合(innerHTMLとほぼ同じ)
inputに入力されたタグがそのままDOMに反映される。
setHTMLの場合(2026年3月時点ではFirefoxのみ)
inputに入力されたタグが除外され、無害化されたテキストのみ(クリックしてください)だけが表示される。