2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ReactAdvent Calendar 2024

Day 24

【React】DOMPurify で XSS 対策

Posted at

はじめに

この記事では、HTML (DOM) の XSS 対策用のライブラリである DOMPurify の React での利用方法について記載します。

開発環境

開発環境は以下の通りです。

  • Windows 11
  • Chrome 131
  • TypeScript 5.5.3
  • React 18.3.1
  • Vite 5.4.7
  • Node.js 20.13.1
  • npm 10.8.1
  • DOMPurify 3.2.3

インストール

まずは DOMPurify をインストールします。

npm i dompurify

DOMPurify を利用しないケース

比較のため、DOMPurify を利用せずに React の dangerouslySetInnerHTML に script タグを渡した時の挙動を確認します。

Unsafe.tsx
import { FC } from "react";

export const Unsafe: FC = () => {
  const potentiallyUnsafeHTML = `
    <div>
      <h2>Hello World!</h2>
      <script>alert('This is unsafe!');</script>
    </div>
  `;

  return (
    <div>
      <h2>Without DOMPurify</h2>
      <div dangerouslySetInnerHTML={{ __html: potentiallyUnsafeHTML }} />
    </div>
  );
};

Chrome の開発者ツールの Elements タブを確認すると、script タグが表示されます。

image.png

DOMPurify を利用するケース

DOMPurify を利用する際は、DOMPurify.sanitize の引数に追加する HTML を渡します。

Safe.tsx
import { FC } from "react";
import DOMPurify from "dompurify";

export const Safe: FC = () => {
  const potentiallyUnsafeHTML = `
    <div>
      <h2>Hello World!</h2>
      <script>alert("This is unsafe!");</script>
    </div>
  `;

  const sanitizedHTML = DOMPurify.sanitize(potentiallyUnsafeHTML);

  return (
    <div>
      <h2>With DOMPurify</h2>
      <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />
    </div>
  );
};

DOMPurify を利用すると、script タグは表示されません。

image.png

画面表示時だけでなく、画面操作時の script も同様に無効化できます。

  • DOMPurify を利用しないケース
Unsafe.tsx
import { FC } from "react";

export const Unsafe: FC = () => {
  const potentiallyUnsafeHTML = `
    <div>
      <button onclick="alert('Still unsafe!')">Click me</button>
    </div>
  `;

  return (
    <div>
      <h2>Without DOMPurify</h2>
      <div dangerouslySetInnerHTML={{ __html: potentiallyUnsafeHTML }} />
    </div>
  );
};

DOMPurify を利用しないと script が実行されます。

Vite-React-TS-Google-Chrome-2024-12-25-09-23-45.gif

  • DOMPurify を利用するケース
Safe.tsx
import { FC } from "react";
import DOMPurify from "dompurify";

export const Safe: FC = () => {
  const potentiallyUnsafeHTML = `
    <div>
      <button onclick="alert('Still unsafe!')">Click me</button>
    </div>
  `;

  const sanitizedHTML = DOMPurify.sanitize(potentiallyUnsafeHTML);

  return (
    <div>
      <h2>With DOMPurify</h2>
      <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />
    </div>
  );
};

DOMPurify を利用すると script は実行されません。

Vite-React-TS-Google-Chrome-2024-12-25-09-23-25_1.gif

タブナビング攻撃などの対象になる脆弱性を持つ target=”_blank” も無効化してくれます。

  • DOMPurify を利用しないケース
Unsafe.tsx
import { FC } from "react";

export const Unsafe: FC = () => {
  const potentiallyUnsafeHTML = `
    <div>
      <a href="https://example.com" target="_blank">
        Visit Example
      </a>
    </div>
  `;

  return (
    <div>
      <h2>Without DOMPurify</h2>
      <div dangerouslySetInnerHTML={{ __html: potentiallyUnsafeHTML }} />
    </div>
  );
};

image.png

  • DOMPurify を利用するケース
Safe.tsx
import { FC } from "react";
import DOMPurify from "dompurify";

export const Safe: FC = () => {
  const potentiallyUnsafeHTML = `
    <div>
      <a href="https://example.com" target="_blank">
        Visit Example
      </a>
    </div>
  `;

  const sanitizedHTML = DOMPurify.sanitize(potentiallyUnsafeHTML);

  return (
    <div>
      <h2>With DOMPurify</h2>
      <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />
    </div>
  );
};

image.png

参考

2
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?