1. 背景と目的
HTML Agility Pack (HAP) は「ゆるい」HTML も含めて DOM として解析・操作できるため、ユーザ入力を表示する CMS や掲示板で多用されます。しかし、入力 HTML にスクリプトや危険な属性が混在すると クロスサイト・スクリプティング(XSS) が発生します。XSS を確実に防ぐためには、解析後に 危険要素を除去してから 出力する「クリーニングとサニタイズ」工程が必須です。ここで主流となるのが ホワイトリスト方式 です。ブラックリスト方式と異なり、「安全と確認できた要素 だけ を残す」ため漏れが起こりにくいのが利点です。en.wikipedia.org
2. ホワイトリスト方式の基本設計
| 項目 | 内容 |
|---|---|
| 対象 | タグ名 / 属性名 / 属性値(プロトコル・正規表現) |
| 動作 | リスト外は まるごと削除 するか テキスト化 して無効化 |
| 追加ルール | リンク要素の rel="noopener noreferrer" 付与、iframe の sandbox 付与 など安全強制 |
-
タグレベル検査
-
<script>,<object>,<embed>,<link>など実行系タグを全除去
-
-
属性レベル検査
-
すべての
on*(イベント)属性、style属性を基本的に禁止 -
href,srcにはjavascript:,data:text/htmlなど危険プロトコルを拒否
-
-
ネスト・再帰検査
-
HTML を走査しながら 子孫ノード にも再帰的にルールを適用し、汚染の取りこぼしを防止
-
Stack Overflow などでも「タグ/属性がホワイトリストにない場合は再帰的に削除せよ」と議論されています。stackoverflow.com
3. HAP でホワイトリストを実装する 3 つのアプローチ
| アプローチ | 特徴 | 向く場面 |
|---|---|---|
| ① 手書き DOM 走査 | HtmlDocument.DocumentNode.Descendants() を走査し自前で判定 |
ルールが極端に少ない小規模フォーム |
| ② HtmlRuleSanitizer | HAP の上に実装された ホワイトリスト専用サニタイザ。流通する HTML5 ルールを同梱し、タグ/属性/CSS クラス単位で宣言的設定が可能 | コメント欄・リッチテキスト入力など汎用用途 |
| ③ MarkupSanity / Rule-Based Sanitizer | ③も HAP ベースの派生ライブラリ。より細かい正規表現チェックや URL 妥当性検証を内蔵 | URL やメディア埋め込みを厳格に検証したい場合 |
HtmlRuleSanitizer は NuGet で入手でき、標準で「安全な HTML5 サブセット」を用意しています。github.com
4. HtmlRuleSanitizer の具体例
ポイント
-
AllowTag/AllowAttributeで明示的に許可を与える -
AddUrlAttributeを使うとjavascript:など 危険スキーム自動拒否 -
未許可要素は内容も丸ごと除去するため、影響範囲が限定的
5. 手書き DOM 走査での実装勘所
-
タグ判定
-
属性フィルタ
-
Uri.TryCreate(attr.Value, UriKind.Absolute, out var u)で http/https か確認 -
正規表現
^[-a-zA-Z0-9@:%_+.~#?&//=]{1,2048}$で余計な文字を排除
-
-
多重デコード対策
-
HttpUtility.UrlDecodeを 繰り返し 適用し、隠れたjavascript:を検出
-
-
HTML エンティティ化
-
どうしても残したい特殊文字は
HtmlEntity.Entitize(text)で無害化
-
6. ルール更新と運用のベストプラクティス
| 項目 | 推奨策 |
|---|---|
| ルール管理 | 変更点を JSON / YAML で外部化し、CI で単体テストを自動実行 |
| 安全デフォルト | 新タグは「禁止」から入り、必要になった時のみ許可 |
| ライブラリ更新 | HAP・サニタイザを常に最新安定版へ。脆弱性勃発時に迅速更新 |
| テスト | 代表的な XSS ペイロード集 (OWASP) を毎回投入し 回帰試験 |
7. まとめ
-
ホワイトリスト方式 は「安全と確定した最小集合のみを許可」するため、XSS 封じ込めに適しています。
-
HAP 単体でも DOM 走査で実装できますが、HtmlRuleSanitizer など既成ライブラリを使うと宣言的に設定でき保守性が高まります。
-
いずれの手法でも タグ・属性・プロトコル の三層防御と、ルール外要素の 再帰削除 を徹底してください。
-
ルールのバージョン管理と自動テストを取り入れ、「安全デフォルト → 必要に応じて許可」の運用を行うことが長期的な安全性を担保します。
ChatGPT4o 生成日:2025/06/23