JavaScriptのinnerHTMLより安全なsetHTMLを全ブラウザで使用する方法

innerHTMLは危険

フロントエンド開発では、HTML文字列をDOMへ挿入する場面がよくあります。

しかし、innerHTML を安易に使うとXSS(クロスサイトスクリプティング)の温床になります。

XSSとは、Webサイトに悪意のあるスクリプトを仕込み、閲覧したユーザーのブラウザ上で実行させるサイバー攻撃またはその脆弱性のことです。

innerHTMLは文字列をそのままHTMLとして解釈するので、以下のようなコードだとonerrorが実行されて、XSSが成立します。

JavaScript
const h1 = document.querySelector('h1')
h1.innerHTML = 'TEST:<img src=x onerror=alert(1)>'
// <h1>TEST:<img src=x onerror=alert(1)></h1> になって危険

innerHTMLでalertが表示されてしまうサンプル

setHTMLは安全

安全にHTMLを挿入するには、前述のimgタグのonerrorなどの危険なコードを取り除く必要があります。

innerHTMLの代わりにsetHTMLを使用すれば、onerrorなどの危険なコードを取り除いた状態でHTMLのコードを要素に挿入できるので安全です。

JavaScript
const h1 = document.querySelector('h1')
h1.setHTML('TEST:<img src=x onerror=alert(1)>')
// <h1>TEST:<img src=x></h1> になって安全

ここまでで、HTMLを挿入する際はinnerHTMLよりsetHTMLを使用したほうが良いことはわかりましたが、1つ問題があります。

それは使用できるブラウザが少ないことです。

Chromeで使用可能なバージョンは146からですが、2026年2月27日現在のバージョンは145のため使えません。

Microsoft EdgeやSafariに関しては対応されるバージョンすら未定です。

しかし、次項で説明するsetHTMLが使用できない場合はDOMPurifyで安全なコードにして挿入する方法を使用すれば、setHTMLを全ブラウザで使用可能になります。

全ブラウザ対応の安全なsetHTML実装

以下はsetHTMLが使用できない場合はDOMPurifyを使用して、安全にHTMLを挿入するコードです。

DOMPurifyとはXSS対策のためのサニタイズライブラリです。

ユーザー入力や外部HTMLを安全にDOMへ挿入できるように、危険なタグや属性を除去してくれます。

DOMPurifyは「npm i dompurify」でインストールしてから使用します。

JavaScript
import DOMPurify from 'dompurify'

if (!Element.prototype.setHTML) {
  Object.defineProperty(Element.prototype, 'setHTML', {
    configurable: true,
    writable: true,
    value: function setHTML(html) {
      const input = String(html ?? '')
      const config = {
        USE_PROFILES: { html: true },
      }
      const sanitized = DOMPurify.sanitize(input, config)
      this.innerHTML = sanitized
    },
  })
}

const h1 = document.querySelector('h1')
h1.setHTML('TEST:<img src=x onerror=alert(1)>')
// <h1>TEST:<img src=x></h1>

npmを使用していない環境で、HTMLファイル内のscriptタグ内に直接コードが書かれている場合は <script type="module"> に変更し、DOMPurifyをURLからimportして使用してください。

HTML
<h1></h1>
<script type="module">
import DOMPurify from 'https://cdn.jsdelivr.net/npm/dompurify/dist/purify.es.mjs'

if (!Element.prototype.setHTML) {
  Object.defineProperty(Element.prototype, 'setHTML', {
    configurable: true,
    writable: true,
    value: function setHTML(html) {
      const input = String(html ?? '')
      const config = {
        USE_PROFILES: { html: true },
      }
      const sanitized = DOMPurify.sanitize(input, config)
      this.innerHTML = sanitized
    },
  })
}

const h1 = document.querySelector('h1')
h1.setHTML('TEST:<img src=x onerror=alert(1)>')
// <h1>TEST:<img src=x></h1>
</script>

DOMPurifyを併用したsetHTMLのサンプル

まとめ

innerHTMLはWeb開発ではXSSの危険性があるので使うべきではありません。

特定の要素内にHTMLコードを挿入する必要がある場合は、前述の全ブラウザ対応のsetHTMLを使うことを推奨します。