≪ Today I learned. RSS購読
公開日
タグ
JavaScript
著者
ダーシノ

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に入力されたタグが除外され、無害化されたテキストのみ(クリックしてください)だけが表示される。

(ここに出力される)