2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React】DOMPurifyを導入し、dangerouslySetInnerHTMLを使いつつXSSの危険性を低減させる

Posted at

はじめに

とあるReactアプリの実装でユーザーが入力したHTMLをレンダリングして表示させる部分がありました。
レンダリングの方法としてはdangerouslySetInnerHTMLがありましたが、調べるうちにこの方法にはセキュリティ上の脆弱性が存在していることがわかりました。

ここではdangerouslySetInnerHTMLの危険性と、その問題を回避するために採用したDOMPurifyについて書いていきます。

dangerouslySetInnerHTMLとXSSの危険性

ReactでHTMLをレンダリングさせる方法としてはdangerouslySetInnerHTMLが挙げられます。

<div dangerouslySetInnerHTML={( __html: (描画したいHTML) )}>の形で記述することで、レンダリングしたいHTMLをReact上で表示させることができます。

React公式ドキュメント上のサンプルコード

sample.jsx
const markup = { __html: '<p>some raw html</p>' };
return <div dangerouslySetInnerHTML={markup} />;

ただし、dangerouslySetInnerHTMLHTMLとしてスクリプト入りのコードを記述するとそのスクリプトが実行されてしまうという問題を抱えています。

これを悪用してユーザー情報を抜き取ったりサイト上で意図せぬ動作を引き起こさせたりすることがいわゆるXSS=クロスサイトスクリプティングです。

参考

危険なコードの例

※React公式から引用

例えば以下のようなコードがあり、HTMLにスクリプトが書かれているとします。

const post = {
  content: `<img src="" onerror='alert("you were hacked")'>`
};

export default function MarkdownPreview() {
  const markup = { __html: post.content };
  return <div dangerouslySetInnerHTML={markup} />;
}

この場合、contentに書かれたonerror="alert"の処理が走ってしまうことになります。
上記の事象を応用して悪意のあるスクリプトを埋め込むことでXSSが引き起こされてまいます。

XSS対策としてのサニタイズとDOMPurify

dangerouslySetInnerHTMLには上記のようにスクリプトがそのまま実行されてしまう脆弱性が存在します。

その対策として必要になってくるのがサニタイズです。

HTMLや属性値などを出力する際、サニタイズ処理をすることで特別な意味を持つメタ文字を無効化し XSSを防ぐことができます。サニタイズ処理をすることで、例えば<→<、>→>のようにタグを無害な文字列に置き換えることができます。
引用元:https://zenn.dev/oreo2990/articles/d33a264b2d8b4c

上記の処理を行うことでHTMLのレンダリング時にスクリプト部分を除去する必要があります。
Reactでこれを行ってくれるライブラリがDOMPurifyです。

導入方法

①インストール
npm install isomorphic-dompurifyでインストールします。

②インポート
使いたいファイル内でimport DOMPurify from 'isomorphic-dompurify';の形でインポートします。

③対象のHTMLをサニタイズする
HTML要素を囲む外側でDOMPurify.sanitizeを記述します。
DOMPurify.sanitize("記述したいHTML")の形です。

DOMPurifyを使うことの効果

dangerouslySetInnerHTML単体のコード

まずはXSS対策が行われていないdangerouslySetInnerHTMLのコードを見てみます。

no-sanitize.jsx
<div
dangerouslySetInnerHTML={{
  __html: `<img src="" onerror='alert("you were hacked")'>`,
}}

するとHTMLに入っているアラートが実行されてしまいます。
スクリーンショット 2025-05-28 23.39.25 1.png
HTMLを見てみると、onerror属性として意図せぬスクリプトが混入していることがわかります。
スクリーンショット 2025-05-28 23.40.44.png

DOMPurifyを併用したコード

次にDOMPurifyを導入したコードを見てみます。

sanitize.jsx
<div
  dangerouslySetInnerHTML={{
    __html: DOMPurify.sanitize(
      `<img src="" onerror='alert("you were hacked")'>`,
    ),
  }}
></div>

出力されたコードを見てみるとアラートが発生せず、該当の部分からonerror属性の記述が削除されていることがわかりました。そのため悪意のあるスクリプトが実行されずに済んだということです。

image.png

これらのことから、DOMPurifyを使うことでXSS対策に一定の効果があると言えそうです。

最後に

dangerouslySetInnerHTMLはHTML文字列をレンダリングさせるためには便利な反面、そのままでは脆弱性のリスクが潜んでいます。

DOMPurifyなどのサニタイズ方法と併用することで脆弱性を低減させてHTMLレンダリングをすることが可能になります。

参考資料

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?