はじめに
DOMPurify は、Web アプリケーションにおける HTML サニタイズの事実上の標準ライブラリだ。
世界中の大規模サービス(Google, GitHub, Moodle, Discourse, Nextcloud など)が採用しており、その理由は 「速い・安全・堅牢・最新攻撃に追従」 の 4 点に尽きる。
この記事では、DOMPurify の仕組みから実践的な使い方、XSS 全種類への効果、CSP や Trusted Types との併用などをわかりやすく説明する。
1. DOMPurify とは?
DOMPurify は ユーザー入力を HTML として扱う際に、その中から悪意あるコードだけを除去する ライブラリ。
つまり:
-
<b>太字</b>のような 許可したい装飾 HTML はそのまま残し -
<script>...</script>や<img onerror=...>などの XSS 要素は自動で除去する
という、非常に精巧なフィルタリングを行ってくれる。
特徴:
- 超高速
- 超安全
- 更新頻度が高く脆弱性研究に強い
- ほぼ全ブラウザ対応
- サーバー側(Node.js)でも動作
- SVG・MathML なども安全化可能
“サニタイズ=DOMPurify” と言われるほど信頼性が高い。
2. DOMPurify が防げる攻撃
DOMPurify はあらゆる HTML ベースの XSS を防ぐ。
| XSS 種類 | DOMPurify | 備考 |
|---|---|---|
| Stored XSS | ◎ | 完全除去 |
| Reflected XSS | ◎ | 完全除去 |
| DOM-Based XSS(innerHTML) | ◎ | innerHTML 前に sanitize すれば安全 |
| SVG XSS | ◎ | SVG の危険タグ削除 |
| MathML XSS | ◎ | MathML の unsafe 部分を除去 |
| URL ベース XSS | △ | URL sanitization が必要な場合あり |
| Script gadgets | ◎ | 既知の bypass に強い |
現代的 XSS の多くが HTML を経由するため、DOMPurify を使えば攻撃面は劇的に狭まる。
3. 基本的な使い方(最短 2 行)
const clean = DOMPurify.sanitize(userInput);
element.innerHTML = clean;
これだけで、
<script> や onerror、危険属性がすべて除去された安全な HTMLが得られる。
4. 許可したい HTML を制御するオプション
DOMPurify は「ホワイトリスト方式」で動いている。
つまり、許可されていないタグ・属性はすべて除去される。
許可するタグの指定
DOMPurify.sanitize(userInput, {
ALLOWED_TAGS: ['b', 'i', 'a', 'p']
});
許可する属性の指定
DOMPurify.sanitize(userInput, {
ALLOWED_ATTR: ['href', 'target']
});
URL スキームを制限する(必須級)
XSS bypass の定番が href="javascript:alert(1)"。
DOMPurify はこれを自動ブロックするが、さらに堅牢にするなら:
DOMPurify.sanitize(userInput, {
ALLOWED_URI_REGEXP: /^https?:\/\//i
});
HTTPS/HTTP 以外は拒否する設定。
5. “Super Safe Mode”(高度な XSS 防御)
完全に安全な HTML のみ許可する設定:
DOMPurify.sanitize(userInput, {
USE_PROFILES: { html: true }
});
または:
DOMPurify.sanitize(userInput, {
ALLOWED_TAGS: [],
ALLOWED_ATTR: []
});
→ 最強の「完全プレーンテキストモード」。
6. Node.js / SSR でも使える
サーバー側レンダリング時の XSS を防ぐことも可能。
const createDOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
const clean = DOMPurify.sanitize(dirtyHTML);
Next.js、Nuxt など SSR ベースのフレームワークでも使用可能。
7. DOMPurify × Trusted Types(XSS 完全封殺コンボ)
DOMPurify は強いが、innerHTML の危険性そのものが消えるわけではない。
そこで併用すべきなのが Trusted Types。
Trusted Types の CSP 設定
Content-Security-Policy:
require-trusted-types-for 'script';
trusted-types dompurify;
DOMPurify を Trusted Types 化
const policy = trustedTypes.createPolicy('dompurify', {
createHTML: (input) => DOMPurify.sanitize(input)
});
element.innerHTML = policy.createHTML(userInput);
これにより:
- DOMPurify 以外から innerHTML に HTML を流し込めない
- “開発者のミス” 自体が技術的にブロックされる
- DOM XSS が ほぼ完全に封じられる
Google の推奨構成でもある。
8. DOMPurify の弱点と注意点
弱点というより、認識すべき仕様。
| 注意点 | 説明 |
|---|---|
| JS 文脈のエスケープはできない |
<script> は除去できるが JS の中に文字列として埋め込む場合は別対策が必要 |
| URL sanitization は別処理が必要 |
javascript: などは除去されるが設計上の考慮が必要 |
| 完全にフレームワーク任せは危険 | React/Vue の dangerous API には要注意 |
| HTML5 の仕様変更に追従するため更新が必要 | 最新版を使うのが必須 |
“DOMPurify だけで XSS 全部を倒せる”は誤解。
あくまで HTML サニタイズ担当。
9. 現代の最強構成:DOMPurify + CSP + Trusted Types
XSS を本気で防ぎたいなら、この 3 点セットが最強。
| レイヤー | 防ぐもの |
|---|---|
| 出力エスケープ | 基本の XSS 70% |
| DOMPurify | HTML ベースの XSS を ほぼ無力化 |
| CSP(script-src 'self') | 攻撃者の JS 実行自体を阻止 |
| Trusted Types | innerHTML の危険性をゼロにする |
この構成を採用すると、
実質的に XSS の攻撃面が枯渇する。
まとめ:DOMPurify は“使わない理由がない”最強ライブラリ
DOMPurify は:
- 速い
- 安全
- 堅牢
- 更新が早い
- 大規模サービスでも運用実績豊富
という、サニタイズ界のオールラウンダー。
もちろん DOMPurify だけで万能ではないが、
“HTML をユーザーに見せる Web アプリで必須級” の存在であることは間違いない。
ユーザーが入力する“HTML”がある限り、DOMPurify の出番は終わらない。