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

    (ここに出力される)