HTML サニタイザー API

コミュニティグループ報告(ドラフト),

このバージョン:
https://wicg.github.io/sanitizer-api/
課題追跡:
GitHub
編集者:
Frederik Braun (Mozilla)
Mario Heiderich (Cure53)
Daniel Vogelheim (Google LLC)
Tom Schuster (Mozilla)

概要

本書は、信頼できない HTML 入力を受け取り、文書の DOM に安全に挿入できるようにサニタイズするための API 群を規定します。

この文書の位置付け

この仕様は Web Platform Incubator Community Group によって公開されました。 これは W3C 標準ではなく、W3C 標準化トラック上にもありません。 なお、 W3C Community Contributor License Agreement (CLA) に基づき、限定的なオプトアウトおよびその他の条件が適用されます。 詳細は W3C の Community および Business Group をご覧ください。

1. 導入

この節は規範ではありません。

Web アプリケーションはクライアント側で HTML 文字列を扱う必要がしばしばあります。 これはクライアントサイドのテンプレート ソリューションの一部であったり、ユーザー生成コンテンツのレンダリングの一部であったりします。これを安全に行うのは難しいです。 文字列を安易に連結して ElementinnerHTML に流し込む素朴な手法は、多くの予期しない形で JavaScript の実行を引き起こし得るため、危険が伴います。

[DOMPURIFY] のようなライブラリは、 挿入前に文字列を注意深く解析・サニタイズし、DOM を構築して許可リストを通してその構成要素をフィルタリングすることで、この問題に対処しようとします。 しかしこれは脆いアプローチであることが分かっています。というのも、Web に公開されている解析 API は、実際に 文字列を「実際の」DOM としてレンダリングする際のブラウザーの挙動と、必ずしも合理的に一致しないからです。 さらに、ライブラリは時間とともに変化するブラウザーの挙動を追い続ける必要があります。かつて安全だったものが、 プラットフォームレベルの新機能によって時限爆弾になってしまうこともあります。

ブラウザーは、自身がいつコードを実行するかについてかなり把握しています。任意の文字列から HTML を安全にレンダリングする方法を ブラウザー自身に教えることで、ユーザー空間のライブラリよりも改善できます。そうすれば、ブラウザーのパーサー実装の変更に合わせて 保守・更新される可能性もはるかに高くなります。本書は、そのための API を概説します。

1.1. 目標

1.2. API 概要

Sanitizer API は、HTML を含む文字列を DOM ツリーに解析し、結果のツリーをユーザー指定の構成に従って フィルタリングする機能を提供します。メソッドは 2 つの観点で用意されています:

2. フレームワーク

2.1. サニタイザー API

Element インターフェイスは、setHTML()setHTMLUnsafe() の 2 つのメソッドを定義します。いずれも HTML マークアップを含む DOMString と、任意の構成を受け取ります。

partial interface Element {
  [CEReactions] undefined setHTMLUnsafe((TrustedHTML or DOMString) html, optional SetHTMLUnsafeOptions options = {});
  [CEReactions] undefined setHTML(DOMString html, optional SetHTMLOptions options = {});
};
ElementsetHTMLUnsafe(html, options) メソッドの手順は次のとおりです:
  1. compliantHTML を、get trusted type compliant string アルゴリズムに TrustedHTMLthis関連グローバルオブジェクトhtml、"Element setHTMLUnsafe"、および "script" を与えて呼び出した結果とする。

  2. target を、thistemplate 要素である場合はその template contents、そうでない場合は this とする。

  3. Set and filter HTML を、targetthiscompliantHTMLoptions、false を与えて実行する。

ElementsetHTML(html, options) メソッドの手順は次のとおりです:
  1. target を、thistemplate の場合はその template contents、 そうでない場合は this とする。

  2. Set and filter HTML を、targetthishtmloptions、true を与えて実行する。

partial interface ShadowRoot {
  [CEReactions] undefined setHTMLUnsafe((TrustedHTML or DOMString) html, optional SetHTMLUnsafeOptions options = {});
  [CEReactions] undefined setHTML(DOMString html, optional SetHTMLOptions options = {});
};

これらのメソッドは ShadowRoot にも反映されています:

ShadowRootsetHTMLUnsafe(html, options) メソッドの手順は次のとおりです:
  1. compliantHTML を、get trusted type compliant string アルゴリズムに、 TrustedHTMLthis関連グローバルオブジェクトhtml、"ShadowRoot setHTMLUnsafe"、および "script" を与えて呼び出した結果とする。

  2. Set and filter HTMLthisthisshadow host(コンテキスト要素として)、 compliantHTMLoptions、false を与えて実行する。

ShadowRootsetHTML(html, options) メソッドの手順は次のとおりです:
  1. Set and filter HTML を、this(target として)、this(コンテキスト 要素として)、 htmloptions、true を与えて実行する。

Document インターフェイスは、文書全体を解析する 2 つの新しいメソッドを得ます:

partial interface Document {
  static Document parseHTMLUnsafe((TrustedHTML or DOMString) html, optional SetHTMLUnsafeOptions options = {});
  static Document parseHTML(DOMString html, optional SetHTMLOptions options = {});
};
parseHTMLUnsafe(html, options) メソッドの手順は次のとおりです:
  1. compliantHTML を、get trusted type compliant string アルゴリズムに、 TrustedHTML現在のグローバルオブジェクトhtml、"Document parseHTMLUnsafe"、および "script" を与えて呼び出した結果とする。

  2. document を新しい Document とし、 その content type は "text/html" とする。

    注: document には browsing context がないため、 スクリプティングは無効です。

  3. documentallow declarative shadow roots を true に設定する。

  4. Parse HTML from a stringdocumentcompliantHTML を与えて実行する。

  5. sanitizer を、get a sanitizer instance from optionsoptions と false を与えて呼び出した結果とする。

  6. sanitizedocument に対して sanitizer と false を与えて呼び出す。

  7. document を返す。

parseHTML(html, options) メソッドの手順は次のとおりです:
  1. document を新しい Document とし、 その content type は "text/html" とする。

    注: document には browsing context がないため、 スクリプティングは無効です。

  2. documentallow declarative shadow roots を true に設定する。

  3. Parse HTML from a stringdocumenthtml を与えて実行する。

  4. sanitizer を、get a sanitizer instance from optionsoptions と true を与えて呼び出した結果とする。

  5. sanitizedocument に対して sanitizer と true を与えて呼び出す。

  6. document を返す。

2.2. SetHTML のオプションと構成オブジェクト。

setHTML() 系の メソッドはすべて options ディクショナリを受け取ります。現時点では、このディクショナリのメンバーは 1 つだけ定義されています:

enum SanitizerPresets { "default" };
dictionary SetHTMLOptions {
  (Sanitizer or SanitizerConfig or SanitizerPresets) sanitizer = "default";
};
dictionary SetHTMLUnsafeOptions {
  (Sanitizer or SanitizerConfig or SanitizerPresets) sanitizer = {};
};

Sanitizer 構成オブジェクトは、フィルター構成をカプセル化します。 同じ構成は "safe" または "unsafe" の両方のメソッドで使用でき、「safe」メソッドは渡された構成に対して暗黙に removeUnsafe を行い、構成が渡されない場合は既定の構成を用います。既定は「safe」と「unsafe」で異なります: 「safe」メソッドは既定で安全であることを目指し制限的で、「unsafe」メソッドは既定で無制限です。 構成の利用意図としては、ページのライフタイムの早い段階で 1 つ(または少数)の構成を作成し、必要に応じて再利用することです。これにより実装は構成を前処理できます。

構成オブジェクトは、構成ディクショナリを返すようにクエリできます。また、直接変更することもできます。

[Exposed=Window]
interface Sanitizer {
  constructor(optional (SanitizerConfig or SanitizerPresets) configuration = "default");

  // Query configuration:
  SanitizerConfig get();

  // Modify a Sanitizer’s lists and fields:
  boolean allowElement(SanitizerElementWithAttributes element);
  boolean removeElement(SanitizerElement element);
  boolean replaceElementWithChildren(SanitizerElement element);
  boolean allowAttribute(SanitizerAttribute attribute);
  boolean removeAttribute(SanitizerAttribute attribute);
  boolean setComments(boolean allow);
  boolean setDataAttributes(boolean allow);

  // Remove markup that executes script.
  boolean removeUnsafe();
};

Sanitizer には対応する SanitizerConfigconfiguration が関連付けられています。

constructor(configuration) メソッドの手順は次のとおりです:
  1. configurationSanitizerPresetsstring である場合:

    1. Assert: configurationis default である。

    2. configurationbuilt-in safe default configuration に設定する。

  2. valid を、set a configurationconfiguration と true を与えて this に対して実行した戻り値とする。

  3. valid が false の場合、TypeError を投げる。

get() メソッドの手順は次のとおりです:
注記: get() メソッドの外では、Sanitizer の要素および属性の順序は観測不可能である。 このメソッドの結果を明示的にソートすることで、例えば内部で順序なし集合を用いるなど、 実装に最適化の機会を与える。
  1. configthisconfiguration とする。

  2. アサート: config有効 である。

  3. もし config["elements"] が 存在するなら:

    1. 任意の config["elements"] の element について:

      1. もし element["attributes"] が 存在するなら:

        1. element["attributes"] を、昇順に並べ替える結果に設定する。 このとき attrAより小さい項目 attrB とする。

      2. もし element["removeAttributes"] が 存在するなら:

        1. element["removeAttributes"] を、昇順に並べ替える結果に設定する。 このとき attrAより小さい項目 attrB とする。

    2. config["elements"] を、昇順に並べ替える結果に設定する。 このとき config["elements"] に対し、 elementAより小さい項目 elementB とする。

  4. さもなくば:

    1. config["removeElements"] を、昇順に並べ替える結果に設定する。 このとき config["removeElements"] に対し、 elementAより小さい項目 elementB とする。

  5. もし config["replaceWithChildrenElements"] が 存在するなら:

    1. config["replaceWithChildrenElements"] を、昇順に並べ替える結果に設定する。 このとき config["replaceWithChildrenElements"] に対し、 elementAより小さい項目 elementB とする。

  6. もし config["attributes"] が 存在するなら:

    1. config["attributes"] を、昇順に並べ替える結果に設定する。 このとき config["attributes"] に対し、 attrAより小さい項目 attrB とする。

  7. さもなくば:

    1. config["removeAttributes"] を、昇順に並べ替える結果に設定する。 このとき config["removeAttributes"] に対し、 attrAより小さい項目 attrB とする。

  8. config を返す。

allowElement(element) メソッドの手順は次のとおりです:
注記: このアルゴリズムは比較的複雑である。というのも、要素許可リストが要素ごとに属性の許可リストまたは除去リストを指定できるためである。 これにより、次の 4 つのケースを区別する必要がある:
  • グローバルな許可リストか除去リストか、そして

  • それらのリストにすでに element が含まれているかどうか。

  1. configurationthisconfiguration とする。

  2. アサート: configuration有効 である。

  3. element を、属性付き Sanitizer 要素の正規化の 結果に設定する(引数は element)。

  4. もし configuration["elements"] が 存在するなら:

    1. modified を、削除 の結果に設定する。 対象は configuration["replaceWithChildrenElements"] からの element である。

    2. コメント: 要素ごとの属性が グローバル属性と重複しないようにする必要がある。

    3. もし configuration["attributes"] が 存在するなら:

      1. もし element["attributes"] が 存在するなら:

        1. element["attributes"] を、重複を除去 した結果に設定する。

        2. element["attributes"] を、 差集合の結果に設定する。 対象は element["attributes"] から configuration["attributes"] を引いたものである。

        3. もし configuration["dataAttributes"] が true なら:

          1. 削除: element["attributes"] から、カスタムデータ属性 である すべての item を取り除く。

      2. もし element["removeAttributes"] が 存在するなら:

        1. element["removeAttributes"] を、重複を除去 した結果に設定する。

        2. element["removeAttributes"] を、 積集合の結果に設定する。 対象は element["removeAttributes"] と configuration["attributes"] である。

    4. さもなくば:

      1. もし element["attributes"] が 存在するなら:

        1. element["attributes"] を、重複を除去 した結果に設定する。

        2. element["attributes"] を、 差集合の結果に設定する。 対象は element["attributes"] から element["removeAttributes"] を 既定値付き « » として引いたものである。

        3. 削除: element["removeAttributes"] を取り除く。

        4. element["attributes"] を、 差集合の結果に設定する。 対象は element["attributes"] から configuration["removeAttributes"] を引いたものである。

      2. もし element["removeAttributes"] が 存在するなら:

        1. element["removeAttributes"] を、重複を除去 した結果に設定する。

        2. element["removeAttributes"] を、 差集合の結果に設定する。 対象は element["removeAttributes"] から configuration["removeAttributes"] を引いたものである。

    5. もし configuration["elements"] が 含まない element なら:

      1. コメント: これは グローバル許可リストにまだ element が含まれていないケースである。

      2. 追加: elementconfiguration["elements"] に追加する。

      3. true を返す。

    6. コメント: これは グローバル許可リストにすでに element が含まれているケースである。

    7. current element を、 configuration["elements"] 内の item とする。ただし item[name] が 等しい element[name] であり、かつ item[namespace] が 等しい element[namespace] であるもの。

    8. もし element等しい current element ならば、 modified を返す。

    9. 削除: configuration["elements"] から element を取り除く。

    10. 追加: configuration["elements"] に element を追加する。

    11. true を返す。

  5. さもなくば:

    1. もし element["attributes"] が 存在する または element["removeAttributes"] が 既定値付き « » で ではないなら:

      1. ユーザーエージェントは、この操作がサポートされていないことを コンソールに警告として報告 してもよい。

      2. false を返す。

    2. modified を、削除 の結果に設定する。 対象は configuration["replaceWithChildrenElements"] からの element である。

    3. もし configuration["removeElements"] が 含まない element なら:

      1. コメント: これは グローバル除去リストに element が含まれていないケースである。

      2. modified を返す。

    4. コメント: これは グローバル除去リストに element が含まれているケースである。

    5. 削除: configuration["removeElements"] から element を取り除く。

    6. true を返す。

removeElement(element) メソッドの手順は、 要素を除去するelementthisconfiguration で実行することである。
replaceElementWithChildren(element) メソッドの手順は次のとおりです:
  1. configurationthisconfiguration とする。

  2. アサート: configuration有効 である。

  3. element を、Sanitizer 要素の正規化 の結果に設定する(引数は element)。

  4. もし configuration["replaceWithChildrenElements"] が 含む element なら:

    1. false を返す。

  5. 削除: configuration["removeElements"] から element を取り除く。

  6. 削除: configuration["elements"] リストから element を取り除く。

  7. 追加: configuration["replaceWithChildrenElements"] に element を追加する。

  8. true を返す。

allowAttribute(attribute) メソッドの手順は 次のとおりです:
注記: このメソッドは、グローバル許可リストがあるか、グローバル除去リストがあるかの 2 つのケースを区別する。 グローバル許可リストに attribute を追加する場合、有効性基準を維持するために、 要素ごとの許可/除去リストの調整が必要になることがある。
  1. configurationthisconfiguration とする。

  2. アサート: configuration有効 である。

  3. attribute を、Sanitizer 属性の正規化 の結果に設定する(引数は attribute)。

  4. もし configuration["attributes"] が 存在するなら:

    1. コメント: グローバル許可リストがある場合、 attribute を追加する必要がある。

    2. もし configuration["dataAttributes"] が true で、かつ attributeカスタムデータ属性 であるなら、false を返す。

    3. もし configuration["attributes"] が 含む attribute なら、 false を返す。

    4. コメント: 要素ごとの許可/除去リストを 調整する。

    5. もし configuration["elements"] が 存在するなら:

      1. element について( configuration["elements"] 内):

        1. もし element["attributes"] が 既定値付き « » で 含む attribute なら:

          1. 削除: element["attributes"] から attribute を取り除く。

        2. アサート: element["removeAttributes"] は 既定値付き « » において 含まない attribute

    6. 追加: configuration["attributes"] に attribute を追加する。

    7. true を返す。

  5. さもなくば:

    1. コメント: グローバル除去リストがある場合、 attribute を除去する必要がある。

    2. もし configuration["removeAttributes"] が 含まない attribute なら:

      1. false を返す。

    3. 削除: configuration["removeAttributes"] から attribute を取り除く。

    4. true を返す。

removeAttribute(attribute) メソッドの手順は、 属性を除去するattributethisconfiguration で実行することである。
setComments(allow) メソッドの手順は次のとおりです:
  1. configurationthisconfiguration とする。

  2. アサート: configuration有効 である。

  3. もし configuration["comments"] が 存在し かつ configuration["comments"] が allow と等しいなら、false を返す。

  4. configuration["comments"] を allow に設定する。

  5. true を返す。

setDataAttributes(allow) メソッドの手順は 次のとおりです:
  1. configurationthisconfiguration とする。

  2. アサート: configuration有効 である。

  3. もし configuration["attributes"] が 存在しない なら、false を返す。

  4. もし configuration["dataAttributes"] が allow と等しいなら、false を返す。

  5. もし allow が true なら:

    1. 削除: configuration["attributes"] から、 カスタムデータ属性 である任意の attr を取り除く。

    2. もし configuration["elements"] が 存在するなら:

      1. element について( configuration["elements"] 内):

        1. もし element[attributes] が 存在するなら:

          1. 削除: element[attributes] から、 カスタムデータ属性 である任意の attr を取り除く。

  6. configuration["dataAttributes"] を allow に設定する。

  7. true を返す。

removeUnsafe() メソッドの手順は、 thisconfiguration を、危険なものを除去thisconfiguration に対して呼び出した結果で更新することである。

2.3. 構成ディクショナリ

dictionary SanitizerElementNamespace {
  required DOMString name;
  DOMString? _namespace = "http://www.w3.org/1999/xhtml";
};

// Used by "elements"
dictionary SanitizerElementNamespaceWithAttributes : SanitizerElementNamespace {
  sequence<SanitizerAttribute> attributes;
  sequence<SanitizerAttribute> removeAttributes;
};

typedef (DOMString or SanitizerElementNamespace) SanitizerElement;
typedef (DOMString or SanitizerElementNamespaceWithAttributes) SanitizerElementWithAttributes;

dictionary SanitizerAttributeNamespace {
  required DOMString name;
  DOMString? _namespace = null;
};
typedef (DOMString or SanitizerAttributeNamespace) SanitizerAttribute;

dictionary SanitizerConfig {
  sequence<SanitizerElementWithAttributes> elements;
  sequence<SanitizerElement> removeElements;
  sequence<SanitizerElement> replaceWithChildrenElements;

  sequence<SanitizerAttribute> attributes;
  sequence<SanitizerAttribute> removeAttributes;

  boolean comments;
  boolean dataAttributes;
};

2.4. 構成の不変条件

構成(configuration)は、開発者が自分の目的に合わせて修正することができ、また修正すべきものです。選択肢としては、新しく構成ディクショナリを一から書く、既存のSanitizerの構成を 修正用メソッドで変更する、あるいは既存のget()Sanitizer構成を辞書として取得し、その辞書を編集して新しいSanitizerを作る、などがあります。

空の構成は(setHTMLUnsafe のような "unsafe" メソッドで呼び出した場合に)すべてを許可します。 "default" 構成は組み込みの安全な既定構成を含みます。なお、「safe」と「unsafe」のサニタイザーメソッドは既定値が異なります。

すべての構成ディクショナリが有効とは限りません。有効な構成は、冗長(同じ要素を二重に許可するなど)や矛盾(同じ要素を削除と許可の両方に指定するなど)を避けます。

構成が有効であるためには、いくつかの条件を満たす必要があります:

elements の要素許可リストは、特定の要素に対して、属性を許可または除去することも指定できる。これは [HTML] の構造(特定の要素に適用されるローカルな attributes と、 global attributes の両方を持つ)を反映することを意図している。グローバル属性とローカル属性は混在可能だが、 ある属性が一方のリストで許可され、他方のリストで禁止されるような曖昧な構成は、一般に無効であることに注意。

グローバル attributes グローバル removeAttributes
ローカル attributes 属性は、いずれかのリストに一致すれば許可される。重複は許可されない。 属性はローカル許可リストにある場合にのみ許可される。 グローバル除去リストとローカル許可リストの間で重複エントリは許可されない。 この特定の要素に関してはグローバル除去リストは機能を持たないが、ローカル許可リストを持たない他の要素には適用されうる点に注意。
ローカル removeAttributes 属性は、グローバル許可リストに含まれ、かつローカル除去リストに含まれない場合に許可される。ローカル除去はグローバル許可リストの部分集合でなければならない。 属性はどちらのリストにもない場合に許可される。 グローバル除去リストとローカル除去リストの間で重複エントリは許可されない。

多くの場合、グローバルと要素ごとのリスト間で重複が許されない非対称性に注意されたい。ただし、グローバル許可リストと要素ごとの除去リストの組み合わせの場合は、後者は前者の部分集合でなければならない。上記表の重複にのみ焦点を当てた抜粋は次のとおり:

グローバル attributes グローバル removeAttributes
ローカル attributes 重複は許可されない。 重複は許可されない。
ローカル removeAttributes ローカル除去はグローバル許可リストの部分集合でなければならない。 重複は許可されない。

dataAttributes 設定は、custom data attributes を許可する。上記の規則は、dataAttributes を許可リストと見なせば、custom data attributes にも容易に拡張できる:

グローバル attributesdataAttributes が設定されている
ローカル attributes すべての custom data attributes が許可される。重複となるため、いかなる custom data attributes もいかなる許可リストにも列挙してはならない。
ローカル removeAttributes custom data attribute は、ローカル除去リストに列挙されていない限り許可される。 重複となるため、いかなる custom data attribute もグローバル許可リストに列挙してはならない。

これらの規則を言葉でまとめると:

SanitizerConfig config は、次の条件がすべて成り立つときに valid である:
  1. config は、elements または removeElements のいずれかの key を持つが、両方は持たない。

  2. config は、attributes または removeAttributes のいずれかの key を持つが、両方は持たない。

  3. Assert: SanitizerElementNamespaceWithAttributesSanitizerElementNamespace、 および SanitizerAttributeNamespace の項目はすべて正規化されている(適切に canonicalize a sanitizer element または canonicalize a sanitizer attribute が実行されている)こと。

  4. config[elements]、 config[removeElements]、 config[replaceWithChildrenElements]、 config[attributes]、 および config[removeAttributes] は、存在する 場合でも、 重複を持たない

  5. config[elements] と config[replaceWithChildrenElements] がいずれも 存在する 場合、 config[elements] と config[replaceWithChildrenElements] の intersectionempty である。

  6. config[removeElements] と config[replaceWithChildrenElements] がいずれも 存在する 場合、 config[removeElements] と config[replaceWithChildrenElements] の intersectionempty である。

  7. config[attributes] が 存在する 場合:

    1. config[elements] が 存在する 場合:

      1. config[elements] の element について:

        1. element[attributes] も element[removeAttributes] も(存在するなら)重複を持たない

        2. config[attributes] と element[attributes] の 既定値付き « » における intersectionempty である。

        3. element[removeAttributes] の 既定値付き « » は、 config[attributes] の subset である。

        4. dataAttributes存在 し、かつ dataAttributes が true の場合:

          1. element[attributes] は custom data attribute を含まない。

    2. アサート: config[dataAttributes] 存在する

    3. dataAttributes が true の場合:

      1. config[attributes] は custom data attribute を含まない。

  8. config[removeAttributes] が 存在する 場合:

    1. config[elements] が 存在する 場合、 config[elements] の element について:

      1. element[attributes] と element[removeAttributes] が同時に 存在 してはならない。

      2. element[attributes] も element[removeAttributes] も(存在するなら)重複を持たない

      3. config[removeAttributes] と element[attributes] の 既定値付き « » における intersectionempty である。

      4. config[removeAttributes] と element[removeAttributes] の 既定値付き « » における intersectionempty である。

    2. config[dataAttributes] は 存在しない

Note: 設定の適用dictionary から行うと、少し正規化が実施される。特に、許可リストと除去リストの双方が欠落している場合、これは空の除去リストとして解釈される。そのため {} 自体は valid な構成ではないが、{removeElements:[],removeAttributes:[]} に正規化され、これは有効である。この正規化ステップは、欠落した dictionary が空のものと一貫するように選ばれており、すなわち setHTMLUnsafe(txt)setHTMLUnsafe(txt, {sanitizer: {}}) と一貫するようにするためである。

3. アルゴリズム

HTML をセットしフィルターするためには、Element または DocumentFragmenttargetElementcontextElement文字列 html辞書 optionsboolean safe を受け取り、次を行う:
  1. もし safe かつ contextElementローカル名 が "script" であり、 contextElement名前空間HTML 名前空間 または SVG 名前空間 の場合、何もせずリターンする。

  2. sanitizerget a sanitizer instance from optionsoptionssafe を与えて呼び出した結果とする。

  3. newChildrenHTML フラグメントパースアルゴリズムcontextElementhtml、true を指定して実行した結果とする。

  4. fragment を新しい DocumentFragment とし、 その ノードドキュメントcontextElementノードドキュメント とする。

  5. newChildren の各 node について、fragment に append する。

  6. sanitizefragmentsanitizersafe で呼び出す。

  7. target の全てを fragment で置き換える

dictionary optionsboolean safe を伴う)から オプションから Sanitizer インスタンスを取得する ために:

Note: このアルゴリズムは SetHTMLOptionsSetHTMLUnsafeOptions の両方で機能する。既定値のみが異なる。

  1. sanitizerSpec を "default" とする。

  2. もし options["sanitizer"] が 存在するなら:

    1. sanitizerSpecoptions["sanitizer"] に設定する。

  3. Assert: sanitizerSpecSanitizer のインスタンス、 string であって SanitizerPresets のメンバー、または dictionary のいずれかである。

  4. もし sanitizerSpecstring なら:

    1. Assert: sanitizerSpecis "default" である。

    2. sanitizerSpec組み込みの安全な既定構成 に設定する。

  5. Assert: sanitizerSpecSanitizer のインスタンス、 または dictionary のいずれかである。

  6. もし sanitizerSpecdictionary なら:

    1. sanitizer を新しい Sanitizer インスタンスとする。

    2. setConfigurationResult を、set a configurationsanitizer 上で sanitizerSpecnot safe を用いて実行した結果とする。

    3. もし setConfigurationResult が false なら、throw により TypeError を投げる。

    4. sanitizerSpecsanitizer に設定する。

  7. Assert: sanitizerSpecSanitizer のインスタンスである。

  8. sanitizerSpec を返す。

3.1. サニタイズ

メインの sanitize 操作として、ParentNode nodeSanitizer sanitizer、そして booleansafe を用いて、次の手順を実行する:
  1. configurationsanitizerconfiguration の値とする。

  2. Assert: configurationvalid である。

  3. もし safe が true なら、configurationconfiguration に対して remove unsafe を呼び出した結果に設定する。

  4. nodeconfiguration に対して sanitize core を呼び出し、さらに handleJavascriptNavigationUrlssafe に設定して実行する。

sanitize core 操作は、ParentNode nodeSanitizerConfig configuration、および booleanhandleJavascriptNavigationUrls を用いて、 node を起点に DOM ツリーを再帰的に処理する。手順は次のとおりである:
  1. For each nodechildrenchild について:

    1. Assert: childimplements TextCommentElement、 または DocumentType である。

      Note: 現在、このアルゴリズムは HTML パーサの出力に対してのみ呼び出され、このアサーションは満たされるはずである。DocumentTypeparseHTML および parseHTMLUnsafe の場合にのみ現れるべきである。将来このアルゴリズムが異なる文脈で用いられるなら、 この前提は再検討される必要がある。

    2. もし childimplements DocumentType なら、continue

    3. もし childimplements Text なら、continue

    4. もし childimplements Comment の場合:

      1. もし configuration["comments"] が true でないなら、 remove child を実行する。

    5. それ以外の場合:

      1. elementName を、childlocal namenamespace を持つ SanitizerElementNamespace とする。

      2. もし configuration["replaceWithChildrenElements"] が exists し、かつ configuration["replaceWithChildrenElements"] が contains elementName の場合:

        1. child に対して、configurationhandleJavascriptNavigationUrls を用いて sanitize core を呼び出す。

        2. replace all を呼び出し、 child 内の childchildren に置き換える。

        3. Continue

      3. もし configuration["elements"] が exists の場合:

        1. もし configuration["elements"] が contain elementName ではないなら:

          1. Remove child

          2. Continue

      4. さもなくば:

        1. もし configuration["removeElements"] が contains elementName の場合:

          1. Remove child

          2. Continue

      5. もし elementNameequals «[ "name" → "template", "namespace" → HTML namespace ]» なら、 configurationhandleJavascriptNavigationUrls を用いて、 childtemplate contents に対して sanitize core を呼び出す。

      6. もし childshadow host であるなら、 configurationhandleJavascriptNavigationUrls を用いて childshadow root に対して sanitize core を呼び出す。

      7. elementWithLocalAttributes を « [] » とする。

      8. もし configuration["elements"] が exists し、 configuration["elements"] が contains elementName の場合:

        1. elementWithLocalAttributesconfiguration["elements"][elementName] に設定する。

      9. For each childattribute list 内の attribute について:

        1. attrName を、attributelocal namenamespace を持つ SanitizerAttributeNamespace とする。

        2. もし elementWithLocalAttributes["removeAttributes"] が with default « » であり、かつ contains attrName の場合:

          1. remove attribute

        3. さもなくば、もし configuration["attributes"] が exists の場合:

          1. もし configuration["attributes"] が contain attrName ではなく、かつ elementWithLocalAttributes["attributes"] が with default « » であり、かつ contain attrName でもなく、さらに "data-" が code unit prefix ではなく、 attributelocal name に対して かつ namespacenull ではない、または configuration["dataAttributes"] が true ではない場合:

            1. remove attribute

        4. それ以外の場合:

          1. もし elementWithLocalAttributes["attributes"] が exists し、かつ elementWithLocalAttributes["attributes"] が contain attrName でないなら:

            1. remove attribute

          2. さもなくば、もし configuration["removeAttributes"] が contains attrName の場合:

            1. remove attribute

        5. もし handleJavascriptNavigationUrls なら:

          1. もし «[elementName, attrName]» が built-in navigating URL attributes list のエントリに一致し、かつ attributecontains a javascript: URL であるなら、remove attribute

          2. もし childnamespaceis MathML Namespace であり、 かつ attrlocal nameis "href" で、attrnamespacenull または XLink namespace であり、 かつ attrcontains a javascript: URL の場合、 remove attribute

          3. もし built-in animating URL attributes listcontains «[elementName, attrName]» で、かつ attrvalueis "href" または "xlink:href" なら、remove attribute

      10. child に対して、configurationhandleJavascriptNavigationUrls を用いて sanitize core を呼び出す。

注: 現在のブラウザは javascript: URL をナビゲーション時のみサポートします。ナビゲーション自体は XSS 脅威ではないため、ナビゲーション先が javascript: URL である場合のみ対応し、他のナビゲーション一般は扱いません。

宣言的ナビゲーションにはいくつか種類があります:

  1. アンカー要素。(HTML・SVG 名前空間の <a>

  2. フォーム要素(form action の一部としてナビゲーションを引き起こす)。

  3. [MathML] では 任意の要素をアンカー化可能

  4. [SVG11] のアニメーション。

最初の2つは 組み込みナビゲーションURL属性リスト でカバーされます。

MathML の場合は別ルールで対処します。本仕様には「名前空間ごとのグローバル」ルールの形式がないためです。

SVG のアニメーション要素は 組み込みアニメーションURL属性リスト でカバーされますが、 SVG アニメーション要素の解釈はアニメーション対象に依存し、サニタイズ中はその対象がわからないため、sanitize アルゴリズムは href 属性のアニメーション自体をブロックします。

attributejavascript: URL を含むか判定するには:
  1. urlattribute に対して 基本URLパーサ を実行した結果とする。

  2. もし urlfailure なら false を返す。

  3. urlscheme が "javascript" と等しいかどうか返す。

3.2. 構成の変更

構成修正メソッドは Sanitizer 上のメソッドであり、 その構成内容を変更します。 これらのメソッドは有効性基準を維持します。 返り値はブーリアンで、構成が変更されたかどうかを呼び出し元に伝えます。

let s = new Sanitizer({elements: ["div"]});
s.allowElement("p"); // true を返す。
div.setHTML("<div><p>", {sanitizer: s});  // `<div>` と `<p>` を許可。
let s = new Sanitizer({elements: ["div"]});
s.removeElement("p");  // false を返す。なぜなら <p> はまだ許可されていないから。
div.setHTML("<div><p>", {sanitizer: s});  // `<div>` は許可、`<p>` は削除される。
SanitizerElement elementSanitizerConfig configuration から 要素を除去する には:
注記: このメソッドでは次の 4 つのケースを区別する必要がある:
  • グローバル許可リストか除去リストか、

  • それらにすでに element が含まれているかどうか。

  1. アサート: configuration有効 である。

  2. element を、Sanitizer 要素の正規化element に対して行った結果に設定する。

  3. modified を、 remove により configuration["replaceWithChildrenElements"] から element を取り除いた結果に設定する。

  4. もし configuration["elements"] が 存在するなら:

    1. もし configuration["elements"] が 含む element なら:

      1. コメント: グローバル許可リストがあり、element を含んでいる。

      2. Remove により configuration["elements"] から element を取り除く。

      3. true を返す。

    2. コメント: グローバル許可リストがあるが、element は含まれていない。

    3. modified を返す。

  5. さもなくば:

    1. もし configuration["removeElements"] が 含む element なら:

      1. コメント: グローバル除去リストがあり、すでに element を含んでいる。

      2. modified を返す。

    2. コメント: グローバル除去リストがあるが、element は含まれていない。

    3. Add により elementconfiguration["removeElements"] に追加する。

    4. true を返す。

SanitizerAttribute attributeSanitizerConfig configuration から 属性を除去する には:

注記: このメソッドは 2 つの場合を区別する。すなわち、グローバル許可リストがあるか、グローバル除去リストがあるかである。グローバル除去リストに attribute を追加する場合、有効性基準を維持するために要素ごとの許可/除去リストの手直しが必要となることがある。グローバル許可リストから attribute を削除する場合、ローカルの除去リストからも当該属性を削除しなければならないことがある。

  1. アサート: configuration有効 である。

  2. attribute を、Sanitizer 属性の正規化attribute に対して行った結果に設定する。

  3. もし configuration["attributes"] が 存在するなら:

    1. コメント: グローバル許可リストがある場合、attribute を追加する必要がある。

    2. もし configuration["attributes"] が 含む attribute でないなら:

      1. false を返す。

    3. コメント: 要素ごとの許可/除去リストを手直しする。

    4. もし configuration["elements"] が 存在するなら:

      1. configuration["elements"] の element について:

        1. もし element["removeAttributes"] が 既定値付き « » で 含む attribute の場合:

          1. Remove により element["removeAttributes"] から attribute を取り除く。

    5. Remove により configuration["attributes"] から attribute を取り除く。

    6. true を返す。

  4. さもなくば:

    1. コメント: グローバル除去リストがある場合、attribute を追加する必要がある。

    2. もし configuration["removeAttributes"] が 含む attribute なら false を返す。

    3. コメント: 要素ごとの許可/除去リストを手直しする。

    4. もし configuration["elements"] が 存在するなら:

      1. configuration["elements"] の element について:

        1. もし element["attributes"] が 既定値付き « » で 含む attribute の場合:

          1. Remove により element["attributes"] から attribute を取り除く。

        2. もし element["removeAttributes"] が 既定値付き « » で 含む attribute の場合:

          1. Remove により element["removeAttributes"] から attribute を取り除く。

    5. Append により attributeconfiguration["removeAttributes"] に追加する。

    6. true を返す。

SanitizerConfig configuration から unsafe を除去する には、 次を行う:

注記: このアルゴリズムの名称は remove unsafe であるが、 "unsafe" という用語は本仕様における厳密な意味で用いており、 文書へ挿入されたときに JavaScript が実行されるコンテンツを指す。言い換えると、このメソッドは XSS の機会を取り除く。

  1. アサート: key setbuilt-in safe baseline configuration の) は equals «[ "removeElements", "removeAttributes" ] » である。

  2. アサート: configuration有効 である。

  3. result を false とする。

  4. elementbuilt-in safe baseline configuration[removeElements] 内) について:

    1. 要素を除去する を呼び出し、 configuration から element を除去する。

    2. 呼び出しが true を返したら、result を true に設定する。

  5. attributebuilt-in safe baseline configuration[removeAttributes] 内) について:

    1. 属性を除去する を呼び出し、 configuration から attribute を除去する。

    2. 呼び出しが true を返したら、result を true に設定する。

  6. イベントハンドラー・コンテンツ属性に列挙された attribute について:

    1. 属性を除去する を呼び出し、 configuration から attribute を除去する。

    2. 呼び出しが true を返したら、result を true に設定する。

  7. result を返す。

3.3. 構成を設定する

構成を設定するには、辞書 configurationboolean allowCommentsAndDataAttributesSanitizer sanitizer を受け取り、次を行う:
  1. canonicalize configuration with allowCommentsAndDataAttributes を実行する。

  2. もし configuration有効 でない場合、false を返す。

  3. sanitizerconfigurationconfiguration に設定する。

  4. true を返す。

3.4. 構成の正規化

Sanitizerconfiguration を正規化された形式で保存します。これにより様々な処理ステップが簡単になります。

elements リスト {elements: ["div"]}{elements: [{name: "div", namespace: "http://www.w3.org/1999/xhtml"}]} のように保存されます。
設定を正規化する SanitizerConfig configurationboolean 型の allowCommentsAndDataAttributes を用いて:

注: configuration[WebIDL] によって JavaScript の値が SanitizerConfig へ変換された結果であると仮定する。

  1. configuration["elements"] と configuration["removeElements"] のいずれも 存在しない場合、 設定する configuration["removeElements"] を « » に。

  2. configuration["attributes"] と configuration["removeAttributes"] のいずれも 存在しない場合、 設定する configuration["removeAttributes"] を « » に。

  3. configuration["elements"] が 存在する場合:

    1. elements を « » にする。

    2. elementconfiguration["elements"] から取り出し、次を行う:

      1. 次を付加する: サニタイザー要素の属性を正規化する element の結果を elements に。

    3. configuration["elements"] を elements に設定する。

  4. configuration["removeElements"] が 存在する場合:

    1. elements を « » にする。

    2. elementconfiguration["removeElements"] から取り出し、次を行う:

      1. 次を付加する: サニタイザー要素を正規化する element の結果を elements に。

    3. configuration["removeElements"] を elements に設定する。

  5. configuration["replaceWithChildrenElements"] が 存在する場合:

    1. elements を « » にする。

    2. elementconfiguration["replaceWithChildrenElements"] から取り出し、次を行う:

      1. 次を付加する: サニタイザー要素を正規化する element の結果を elements に。

    3. configuration["replaceWithChildrenElements"] を elements に設定する。

  6. configuration["attributes"] が 存在する場合:

    1. attributes を « » にする。

    2. attributeconfiguration["attributes"] から取り出し、次を行う:

      1. 次を付加する: サニタイザー属性を正規化する attribute の結果を attributes に。

    3. configuration["attributes"] を attributes に設定する。

  7. configuration["removeAttributes"] が 存在する場合:

    1. attributes を « » にする。

    2. attributeconfiguration["removeAttributes"] から取り出し、次を行う:

      1. 次を付加する: サニタイザー属性を正規化する attribute の結果を attributes に。

    3. configuration["removeAttributes"] を attributes に設定する。

  8. configuration["comments"] が存在しない場合、 設定する configuration["comments"] を allowCommentsAndDataAttributes に。

  9. configuration["attributes"] が 存在し、かつ configuration["dataAttributes"] が存在しない場合、 設定する configuration["dataAttributes"] を allowCommentsAndDataAttributes に。

canonicalize a sanitizer element with attributes を、SanitizerElementWithAttributes element に対して行うには:
  1. result を、canonicalize a sanitizer elementelement に対して実行した結果とする。

  2. elementdictionary の場合:

    1. element["attributes"] が exists する場合:

      1. attributes を « » とする。

      2. For each element["attributes"] の attribute について:

        1. Append により、 canonicalize a sanitizer attributeattribute に対して実行した結果を attributes に追加する。

      3. Set により result["attributes"] を attributes に設定する。

    2. element["removeAttributes"] が exists する場合:

      1. attributes を « » とする。

      2. For each element["removeAttributes"] の attribute について:

        1. Append により、 canonicalize a sanitizer attributeattribute に対して実行した結果を attributes に追加する。

      3. Set により result["removeAttributes"] を attributes に設定する。

  3. result["attributes"] と result["removeAttributes"] のいずれも exist しない場合:

    1. Set により result["removeAttributes"] を « » に設定する。

  4. result を返す。

canonicalize a sanitizer element を行うにあたり、 SanitizerElement element について、 canonicalize a sanitizer nameelement と 既定の名前空間として HTML namespace を用いて実行した結果を返す。
canonicalize a sanitizer attribute を行うにあたり、 SanitizerAttribute attribute について、 canonicalize a sanitizer nameattribute と既定の名前空間として null を用いて実行した結果を返す。
canonicalize a sanitizer namename に対して、 既定の名前空間 defaultNamespace とともに行うために、次の手順を実行する:
  1. Assert: nameDOMString か、dictionary のいずれかである。

  2. もし nameDOMString なら、 «[ "name" → name, "namespace" → defaultNamespace]» を返す。

  3. Assert: namedictionary であり、 name["name"] と name["namespace"] の両方が exist する。

  4. もし name["namespace"] が空文字列であるなら、null に設定する。

  5. «[
    "name" → name["name"],
    "namespace" → name["namespace"]
    ]» を返す。

3.5. 補助アルゴリズム

この仕様で使われる正規化された elementattribute name のリストでは、 リスト内に含まれるかどうかは "name" と "namespace" の両方の一致によって決まります:

Sanitizer名リスト listcontains item であるとは、 list の中に 順序付きマップである entry が存在し、 item["name"] が entry["name"] と等しく、 item["namespace"] が entry["namespace"] と等しい場合のことです。
removeリスト list から item を削除します:
  1. removed を false にする。

  2. list の各 entry について:

    1. もし item["name"] が entry["name"] と等しく、 item["namespace"] が entry["namespace"] と等しい場合:

      1. entrylist から削除する。

      2. removed を true にする。

  3. removed を返す。

addname(正規化済み)を list順序付きマップ)に追加します:
  1. もし listcontains name なら何もしないでリターン。

  2. appendnamelist の末尾に追加する。

アイテム itemAless than item itemB であるとは:
  1. itemA["namespace"] が null の場合:

    1. itemB["namespace"] が null でない場合、true を返す。

  2. それ以外の場合:

    1. itemB["namespace"] が null の場合、false を返す。

    2. itemA["namespace"] が コード単位で未満 itemB["namespace"] の場合、true を返す。

    3. itemA["namespace"] itemB["namespace"] と等しくない場合、false を返す。

  3. itemA["name"] が コード単位で未満 itemB["name"] であるかを返す。

順序付き集合 の等価性はメンバーの等価性のみで、順序は無視されます: 順序付き集合 ABequal であるとは、 Asuperset かつ Bsuperset のときです。
順序付きマップキータプル列です。 順序付きマップの等価性は、このタプル列を順序付き集合として比較したときの等価性です。 順序付きマップ ABequal であるとは、 順序付き集合としての Aentries順序付き集合としての Bentriesequal である場合です。
リスト listhas duplicates であるとは、 list 内の任意の item について、 item["name"] と item["namespace"] が一致する entry が list 内に2つ以上存在する場合です。
remove duplicatesリスト list から重複を除去します:
  1. result を « » にする。

  2. list の各 entry について、addentryresult に追加する。

  3. result を返す。

2つの リスト ABSanitizerElement に対する intersection集合の積集合ですが、 各エントリは事前に 正規化 されています:
  1. set A を « [] » にする。

  2. set B を « [] » にする。

  3. A の各 entry について set append正規化した結果を set A に追加。

  4. B の各 entry について set append正規化した結果を set B に追加。

  5. set Aset B積集合を返す。

boolean boolnot は、 bool が true なら false、そうでなければ true を返します。
Comment は アルゴリズム中の特定のポイントに対する説明文を含みます。

3.6. 組み込み

組み込みは4つあります:

組み込みの安全な既定構成は次の通りです:

{
  "elements": [
    {
      "name": "math",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "merror",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mfrac",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mi",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mmultiscripts",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mn",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mo",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": [
        {
          "name": "fence",
          "namespace": null
        },
        {
          "name": "form",
          "namespace": null
        },
        {
          "name": "largeop",
          "namespace": null
        },
        {
          "name": "lspace",
          "namespace": null
        },
        {
          "name": "maxsize",
          "namespace": null
        },
        {
          "name": "minsize",
          "namespace": null
        },
        {
          "name": "movablelimits",
          "namespace": null
        },
        {
          "name": "rspace",
          "namespace": null
        },
        {
          "name": "separator",
          "namespace": null
        },
        {
          "name": "stretchy",
          "namespace": null
        },
        {
          "name": "symmetric",
          "namespace": null
        }
      ]
    },
    {
      "name": "mover",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": [
        {
          "name": "accent",
          "namespace": null
        }
      ]
    },
    {
      "name": "mpadded",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": [
        {
          "name": "depth",
          "namespace": null
        },
        {
          "name": "height",
          "namespace": null
        },
        {
          "name": "lspace",
          "namespace": null
        },
        {
          "name": "voffset",
          "namespace": null
        },
        {
          "name": "width",
          "namespace": null
        }
      ]
    },
    {
      "name": "mphantom",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mprescripts",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mroot",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mrow",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "ms",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mspace",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": [
        {
          "name": "depth",
          "namespace": null
        },
        {
          "name": "height",
          "namespace": null
        },
        {
          "name": "width",
          "namespace": null
        }
      ]
    },
    {
      "name": "msqrt",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mstyle",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "msub",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "msubsup",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "msup",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mtable",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mtd",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": [
        {
          "name": "columnspan",
          "namespace": null
        },
        {
          "name": "rowspan",
          "namespace": null
        }
      ]
    },
    {
      "name": "mtext",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "mtr",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "munder",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": [
        {
          "name": "accentunder",
          "namespace": null
        }
      ]
    },
    {
      "name": "munderover",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": [
        {
          "name": "accent",
          "namespace": null
        },
        {
          "name": "accentunder",
          "namespace": null
        }
      ]
    },
    {
      "name": "semantics",
      "namespace": "http://www.w3.org/1998/Math/MathML",
      "attributes": []
    },
    {
      "name": "a",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "href",
          "namespace": null
        },
        {
          "name": "hreflang",
          "namespace": null
        },
        {
          "name": "type",
          "namespace": null
        }
      ]
    },
    {
      "name": "abbr",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "address",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "article",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "aside",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "b",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "bdi",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "bdo",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "blockquote",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "cite",
          "namespace": null
        }
      ]
    },
    {
      "name": "body",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "br",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "caption",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "cite",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "code",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "col",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "span",
          "namespace": null
        }
      ]
    },
    {
      "name": "colgroup",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "span",
          "namespace": null
        }
      ]
    },
    {
      "name": "data",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "value",
          "namespace": null
        }
      ]
    },
    {
      "name": "dd",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "del",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "cite",
          "namespace": null
        },
        {
          "name": "datetime",
          "namespace": null
        }
      ]
    },
    {
      "name": "dfn",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "div",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "dl",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "dt",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "em",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "figcaption",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "figure",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "footer",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "h1",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "h2",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "h3",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "h4",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "h5",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "h6",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "head",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "header",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "hgroup",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "hr",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "html",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "i",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "ins",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "cite",
          "namespace": null
        },
        {
          "name": "datetime",
          "namespace": null
        }
      ]
    },
    {
      "name": "kbd",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "li",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "value",
          "namespace": null
        }
      ]
    },
    {
      "name": "main",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "mark",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "menu",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "nav",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "ol",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "reversed",
          "namespace": null
        },
        {
          "name": "start",
          "namespace": null
        },
        {
          "name": "type",
          "namespace": null
        }
      ]
    },
    {
      "name": "p",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "pre",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "q",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "rp",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "rt",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "ruby",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "s",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "samp",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "search",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "section",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "small",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "span",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "strong",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "sub",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "sup",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "table",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "tbody",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "td",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "colspan",
          "namespace": null
        },
        {
          "name": "headers",
          "namespace": null
        },
        {
          "name": "rowspan",
          "namespace": null
        }
      ]
    },
    {
      "name": "tfoot",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "th",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "abbr",
          "namespace": null
        },
        {
          "name": "colspan",
          "namespace": null
        },
        {
          "name": "headers",
          "namespace": null
        },
        {
          "name": "rowspan",
          "namespace": null
        },
        {
          "name": "scope",
          "namespace": null
        }
      ]
    },
    {
      "name": "thead",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "time",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": [
        {
          "name": "datetime",
          "namespace": null
        }
      ]
    },
    {
      "name": "title",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "tr",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "u",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "ul",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "var",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "wbr",
      "namespace": "http://www.w3.org/1999/xhtml",
      "attributes": []
    },
    {
      "name": "a",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "href",
          "namespace": null
        },
        {
          "name": "hreflang",
          "namespace": null
        },
        {
          "name": "type",
          "namespace": null
        }
      ]
    },
    {
      "name": "circle",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "cx",
          "namespace": null
        },
        {
          "name": "cy",
          "namespace": null
        },
        {
          "name": "pathLength",
          "namespace": null
        },
        {
          "name": "r",
          "namespace": null
        }
      ]
    },
    {
      "name": "defs",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": []
    },
    {
      "name": "desc",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": []
    },
    {
      "name": "ellipse",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "cx",
          "namespace": null
        },
        {
          "name": "cy",
          "namespace": null
        },
        {
          "name": "pathLength",
          "namespace": null
        },
        {
          "name": "rx",
          "namespace": null
        },
        {
          "name": "ry",
          "namespace": null
        }
      ]
    },
    {
      "name": "foreignObject",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "height",
          "namespace": null
        },
        {
          "name": "width",
          "namespace": null
        },
        {
          "name": "x",
          "namespace": null
        },
        {
          "name": "y",
          "namespace": null
        }
      ]
    },
    {
      "name": "g",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": []
    },
    {
      "name": "line",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "pathLength",
          "namespace": null
        },
        {
          "name": "x1",
          "namespace": null
        },
        {
          "name": "x2",
          "namespace": null
        },
        {
          "name": "y1",
          "namespace": null
        },
        {
          "name": "y2",
          "namespace": null
        }
      ]
    },
    {
      "name": "marker",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "markerHeight",
          "namespace": null
        },
        {
          "name": "markerUnits",
          "namespace": null
        },
        {
          "name": "markerWidth",
          "namespace": null
        },
        {
          "name": "orient",
          "namespace": null
        },
        {
          "name": "preserveAspectRatio",
          "namespace": null
        },
        {
          "name": "refX",
          "namespace": null
        },
        {
          "name": "refY",
          "namespace": null
        },
        {
          "name": "viewBox",
          "namespace": null
        }
      ]
    },
    {
      "name": "metadata",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": []
    },
    {
      "name": "path",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "d",
          "namespace": null
        },
        {
          "name": "pathLength",
          "namespace": null
        }
      ]
    },
    {
      "name": "polygon",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "pathLength",
          "namespace": null
        },
        {
          "name": "points",
          "namespace": null
        }
      ]
    },
    {
      "name": "polyline",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "pathLength",
          "namespace": null
        },
        {
          "name": "points",
          "namespace": null
        }
      ]
    },
    {
      "name": "rect",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "height",
          "namespace": null
        },
        {
          "name": "pathLength",
          "namespace": null
        },
        {
          "name": "rx",
          "namespace": null
        },
        {
          "name": "ry",
          "namespace": null
        },
        {
          "name": "width",
          "namespace": null
        },
        {
          "name": "x",
          "namespace": null
        },
        {
          "name": "y",
          "namespace": null
        }
      ]
    },
    {
      "name": "svg",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "height",
          "namespace": null
        },
        {
          "name": "preserveAspectRatio",
          "namespace": null
        },
        {
          "name": "viewBox",
          "namespace": null
        },
        {
          "name": "width",
          "namespace": null
        },
        {
          "name": "x",
          "namespace": null
        },
        {
          "name": "y",
          "namespace": null
        }
      ]
    },
    {
      "name": "text",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "dx",
          "namespace": null
        },
        {
          "name": "dy",
          "namespace": null
        },
        {
          "name": "lengthAdjust",
          "namespace": null
        },
        {
          "name": "rotate",
          "namespace": null
        },
        {
          "name": "textLength",
          "namespace": null
        },
        {
          "name": "x",
          "namespace": null
        },
        {
          "name": "y",
          "namespace": null
        }
      ]
    },
    {
      "name": "textPath",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "lengthAdjust",
          "namespace": null
        },
        {
          "name": "method",
          "namespace": null
        },
        {
          "name": "path",
          "namespace": null
        },
        {
          "name": "side",
          "namespace": null
        },
        {
          "name": "spacing",
          "namespace": null
        },
        {
          "name": "startOffset",
          "namespace": null
        },
        {
          "name": "textLength",
          "namespace": null
        }
      ]
    },
    {
      "name": "title",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": []
    },
    {
      "name": "tspan",
      "namespace": "http://www.w3.org/2000/svg",
      "attributes": [
        {
          "name": "dx",
          "namespace": null
        },
        {
          "name": "dy",
          "namespace": null
        },
        {
          "name": "lengthAdjust",
          "namespace": null
        },
        {
          "name": "rotate",
          "namespace": null
        },
        {
          "name": "textLength",
          "namespace": null
        },
        {
          "name": "x",
          "namespace": null
        },
        {
          "name": "y",
          "namespace": null
        }
      ]
    }
  ],
  "attributes": [
    {
      "name": "alignment-baseline",
      "namespace": null
    },
    {
      "name": "baseline-shift",
      "namespace": null
    },
    {
      "name": "clip-path",
      "namespace": null
    },
    {
      "name": "clip-rule",
      "namespace": null
    },
    {
      "name": "color",
      "namespace": null
    },
    {
      "name": "color-interpolation",
      "namespace": null
    },
    {
      "name": "cursor",
      "namespace": null
    },
    {
      "name": "dir",
      "namespace": null
    },
    {
      "name": "direction",
      "namespace": null
    },
    {
      "name": "display",
      "namespace": null
    },
    {
      "name": "displaystyle",
      "namespace": null
    },
    {
      "name": "dominant-baseline",
      "namespace": null
    },
    {
      "name": "fill",
      "namespace": null
    },
    {
      "name": "fill-opacity",
      "namespace": null
    },
    {
      "name": "fill-rule",
      "namespace": null
    },
    {
      "name": "font-family",
      "namespace": null
    },
    {
      "name": "font-size",
      "namespace": null
    },
    {
      "name": "font-size-adjust",
      "namespace": null
    },
    {
      "name": "font-stretch",
      "namespace": null
    },
    {
      "name": "font-style",
      "namespace": null
    },
    {
      "name": "font-variant",
      "namespace": null
    },
    {
      "name": "font-weight",
      "namespace": null
    },
    {
      "name": "lang",
      "namespace": null
    },
    {
      "name": "letter-spacing",
      "namespace": null
    },
    {
      "name": "marker-end",
      "namespace": null
    },
    {
      "name": "marker-mid",
      "namespace": null
    },
    {
      "name": "marker-start",
      "namespace": null
    },
    {
      "name": "mathbackground",
      "namespace": null
    },
    {
      "name": "mathcolor",
      "namespace": null
    },
    {
      "name": "mathsize",
      "namespace": null
    },
    {
      "name": "opacity",
      "namespace": null
    },
    {
      "name": "paint-order",
      "namespace": null
    },
    {
      "name": "pointer-events",
      "namespace": null
    },
    {
      "name": "scriptlevel",
      "namespace": null
    },
    {
      "name": "shape-rendering",
      "namespace": null
    },
    {
      "name": "stop-color",
      "namespace": null
    },
    {
      "name": "stop-opacity",
      "namespace": null
    },
    {
      "name": "stroke",
      "namespace": null
    },
    {
      "name": "stroke-dasharray",
      "namespace": null
    },
    {
      "name": "stroke-dashoffset",
      "namespace": null
    },
    {
      "name": "stroke-linecap",
      "namespace": null
    },
    {
      "name": "stroke-linejoin",
      "namespace": null
    },
    {
      "name": "stroke-miterlimit",
      "namespace": null
    },
    {
      "name": "stroke-opacity",
      "namespace": null
    },
    {
      "name": "stroke-width",
      "namespace": null
    },
    {
      "name": "text-anchor",
      "namespace": null
    },
    {
      "name": "text-decoration",
      "namespace": null
    },
    {
      "name": "text-overflow",
      "namespace": null
    },
    {
      "name": "text-rendering",
      "namespace": null
    },
    {
      "name": "title",
      "namespace": null
    },
    {
      "name": "transform",
      "namespace": null
    },
    {
      "name": "transform-origin",
      "namespace": null
    },
    {
      "name": "unicode-bidi",
      "namespace": null
    },
    {
      "name": "vector-effect",
      "namespace": null
    },
    {
      "name": "visibility",
      "namespace": null
    },
    {
      "name": "white-space",
      "namespace": null
    },
    {
      "name": "word-spacing",
      "namespace": null
    },
    {
      "name": "writing-mode",
      "namespace": null
    }
  ],
  "comments": false,
  "dataAttributes": false
}

注: 含まれる[MathML] マークアップは [SafeMathML] に基づいています。

組み込みの安全なベースライン構成は、スクリプト内容のみをブロックすることを目的としています。内容は以下の通りです:

{
  "removeElements": [
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "embed"
    },
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "frame"
    },
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "iframe"
    },
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "object"
    },
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "script"
    },
    {
      "namespace": "http://www.w3.org/2000/svg",
      "name": "script"
    },
    {
      "namespace": "http://www.w3.org/2000/svg",
      "name": "use"
    }
  ],
  "removeAttributes": []
}

警告: remove unsafe アルゴリズムは、 イベントハンドラー内容属性[HTML] で定義)も追加で除去することを規定します。 もしユーザーエージェント[HTML]仕様に独自の イベントハンドラー内容属性 を拡張して定義する場合は、その扱い方を決める責任があります。現在の イベントハンドラー内容属性 リストを使うと、安全なベースライン構成は実質的に次のようになります:

{
  "removeElements": [
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "embed"
    },
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "frame"
    },
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "iframe"
    },
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "object"
    },
    {
      "namespace": "http://www.w3.org/1999/xhtml",
      "name": "script"
    },
    {
      "namespace": "http://www.w3.org/2000/svg",
      "name": "script"
    },
    {
      "namespace": "http://www.w3.org/2000/svg",
      "name": "use"
    }
  ],
  "removeAttributes": [
    "onafterprint",
    "onauxclick",
    "onbeforeinput",
    "onbeforematch",
    "onbeforeprint",
    "onbeforeunload",
    "onbeforetoggle",
    "onblur",
    "oncancel",
    "oncanplay",
    "oncanplaythrough",
    "onchange",
    "onclick",
    "onclose",
    "oncontextlost",
    "oncontextmenu",
    "oncontextrestored",
    "oncopy",
    "oncuechange",
    "oncut",
    "ondblclick",
    "ondrag",
    "ondragend",
    "ondragenter",
    "ondragleave",
    "ondragover",
    "ondragstart",
    "ondrop",
    "ondurationchange",
    "onemptied",
    "onended",
    "onerror",
    "onfocus",
    "onformdata",
    "onhashchange",
    "oninput",
    "oninvalid",
    "onkeydown",
    "onkeypress",
    "onkeyup",
    "onlanguagechange",
    "onload",
    "onloadeddata",
    "onloadedmetadata",
    "onloadstart",
    "onmessage",
    "onmessageerror",
    "onmousedown",
    "onmouseenter",
    "onmouseleave",
    "onmousemove",
    "onmouseout",
    "onmouseover",
    "onmouseup",
    "onoffline",
    "ononline",
    "onpagehide",
    "onpagereveal",
    "onpageshow",
    "onpageswap",
    "onpaste",
    "onpause",
    "onplay",
    "onplaying",
    "onpopstate",
    "onprogress",
    "onratechange",
    "onreset",
    "onresize",
    "onrejectionhandled",
    "onscroll",
    "onscrollend",
    "onsecuritypolicyviolation",
    "onseeked",
    "onseeking",
    "onselect",
    "onslotchange",
    "onstalled",
    "onstorage",
    "onsubmit",
    "onsuspend",
    "ontimeupdate",
    "ontoggle",
    "onunhandledrejection",
    "onunload",
    "onvolumechange",
    "onwaiting",
    "onwheel"
  ]
}
組み込みナビゲーションURL属性リスト("javascript:" ナビゲーションが「安全でない」とされる)は以下の通りです:

«[
[ { "name" → "a", "namespace" → HTML namespace }, { "name" → "href", "namespace" → null } ],
[ { "name" → "area", "namespace" → HTML namespace }, { "name" → "href", "namespace" → null } ],
[ { "name" → "base", "namespace" → HTML namespace }, { "name" → "href", "namespace" → null } ],
[ { "name" → "button", "namespace" → HTML namespace }, { "name" → "formaction", "namespace" → null } ],
[ { "name" → "form", "namespace" → HTML namespace }, { "name" → "action", "namespace" → null } ],
[ { "name" → "input", "namespace" → HTML namespace }, { "name" → "formaction", "namespace" → null } ],
[ { "name" → "a", "namespace" → SVG namespace }, { "name" → "href", "namespace" → null } ],
[ { "name" → "a", "namespace" → SVG namespace }, { "name" → "href", "namespace" → XLink namespace } ],

組み込みアニメーションURL属性リストは、 [SVG11] において宣言的にナビゲーション要素を "javascript:" URL へ変更するために使用されることがあります。内容は以下の通りです:

«[
[ { "name" → "animate", "namespace" → SVG namespace }, { "name" → "attributeName", "namespace" → null] } ],
[ { "name" → "animateMotion", "namespace" → SVG namespace }, { "name" → "attributeName", "namespace" → null } ],
[ { "name" → "animateTransform", "namespace" → SVG namespace }, { "name" → "attributeName", "namespace" → null } ],
[ { "name" → "set", "namespace" → SVG namespace }, { "name" → "attributeName", "namespace" → null } ],

4. セキュリティ考慮事項

Sanitizer API は、与えられた HTML コンテンツを走査し、構成に従って要素や属性を除去することで DOM ベースのクロスサイトスクリプティングを防ぐことを目的としています。指定された API は、スクリプト実行可能なマークアップを残すような Sanitizer オブジェクトの構築を許してはならず、もしそうなった場合は脅威モデル上のバグです。

とはいえ、Sanitizer API の正しい利用だけでは防げないセキュリティ上の問題も存在し、それについては以下のセクションで説明します。

4.1. サーバーサイド反射型および保存型XSS

このセクションは規範的ではありません。

Sanitizer API は DOM 内だけで動作し、既存の DocumentFragment を走査・フィルターする機能を提供します。Sanitizer はサーバーサイドの反射型XSSや保存型XSSには対応しません。

4.2. DOMクラッタリング

このセクションは規範的ではありません。

DOMクラッタリングとは、攻撃者が idname 属性を使って要素に名前をつけ、HTML要素の children などのプロパティを悪意のある内容で上書きしてアプリケーションを混乱させる攻撃です。

Sanitizer API はデフォルトでは DOMクラッタリング攻撃を防ぎませんが、構成で idname 属性を除去することができます。

4.3. スクリプトガジェットによるXSS

このセクションは規範的ではありません。

スクリプトガジェットとは、攻撃者が有名なJavaScriptライブラリなどの既存アプリケーションコードを利用して、攻撃者自身のコードを実行させる手法です。これは無害に見えるコードや一見無害なDOMノードを注入し、フレームワークがそれを解析・解釈することで JavaScript の実行につなげます。

Sanitizer API ではこの種の攻撃を防ぐことはできません。ページ作成者は未知の要素を許可する場合は特に注意し、data-slot 属性、<slot><template> など広く使われるテンプレート・フレームワーク固有のマークアップも明示的に設定する必要があります。これらの制限は網羅的ではないので、ページ作成者はサードパーティライブラリの挙動もよく確認してください。

4.4. 変異型XSS

このセクションは規範的ではありません。

変異型XSS(mXSS)は、HTMLスニペットを誤った文脈でパースした際にパーサの文脈不一致を利用する攻撃です。特に、一度パースしたHTMLフラグメントを文字列としてシリアライズし、別の親要素に再挿入した場合、同じように解釈される保証はありません。例えば外部コンテンツやタグの入れ子ミスによるパース挙動の変化を利用します。

Sanitizer API は文字列をノードツリー化する機能のみを提供します。文脈は各サニタイザー関数によって暗黙的に与えられ、Element.setHTML() は現在の要素、Document.parseHTML() は新しいドキュメントを作成します。そのためSanitizer API自体は変異型XSSの直接的な影響は受けません。

もし開発者がサニタイズ済みノードツリーを .innerHTML などで文字列にし、再度パースする場合はmXSSが発生しうるため、この運用は推奨されません。どうしても文字列でHTMLを扱う場合は、その文字列は信頼できないものとして扱い、DOM挿入時に再度サニタイズすべきです。つまり、一度サニタイズ→シリアライズしたHTMLは、もはやサニタイズ済みとは考えられません。

mXSSのより完全な解説は [MXSS] を参照してください。

5. 謝辞

本仕様は cure53 の [DOMPURIFY]、 Internet Explorer の window.toStaticHTML() 、そして Ben Bucksch による [HTMLSanitizer] に着想を得ています。Anne van Kesteren、Krzysztof Kotowicz、 Andrew C. H. Mc Millan、Tom Schuster、Luke Warlow、Guillaume Weghsteen、 Mike West 各氏の貴重なフィードバックにも感謝します。

索引

本仕様で定義される用語

他の仕様で定義される用語

参考文献

規範的な参考文献

[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; 他. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[TRUSTED-TYPES]
Krzysztof Kotowicz. Trusted Types. URL: https://w3c.github.io/trusted-types/dist/spec/
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WebIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

参考情報

[DOMPURIFY]
DOMPurify. URL: https://github.com/cure53/DOMPurify
[HTMLSanitizer]
HTML Sanitizer. URL: https://www.bucksch.org/1/projects/mozilla/108153/
[MathML]
Patrick D F Ion; Robert R Miner. Mathematical Markup Language (MathML™) 1.01 Specification. 2023年3月7日. REC. URL: https://www.w3.org/TR/REC-MathML/
[MXSS]
mXSS Attacks: Attacking well-secured Web-Applications by using innerHTML Mutations. URL: https://cure53.de/fp170.pdf
[SafeMathML]
MathML Safe List. URL: https://w3c.github.io/mathml-docs/mathml-safe-list
[SVG11]
Erik Dahlström; 他. Scalable Vector Graphics (SVG) 1.1 (Second Edition). 2011年8月16日. REC. URL: https://www.w3.org/TR/SVG11/

IDL 索引

enum SanitizerPresets { "default" };
dictionary SetHTMLOptions {
  (Sanitizer or SanitizerConfig or SanitizerPresets) sanitizer = "default";
};
dictionary SetHTMLUnsafeOptions {
  (Sanitizer or SanitizerConfig or SanitizerPresets) sanitizer = {};
};

[Exposed=Window]
interface Sanitizer {
  constructor(optional (SanitizerConfig or SanitizerPresets) configuration = "default");

  // Query configuration:
  SanitizerConfig get();

  // Modify a Sanitizer’s lists and fields:
  boolean allowElement(SanitizerElementWithAttributes element);
  boolean removeElement(SanitizerElement element);
  boolean replaceElementWithChildren(SanitizerElement element);
  boolean allowAttribute(SanitizerAttribute attribute);
  boolean removeAttribute(SanitizerAttribute attribute);
  boolean setComments(boolean allow);
  boolean setDataAttributes(boolean allow);

  // Remove markup that executes script.
  boolean removeUnsafe();
};

dictionary SanitizerElementNamespace {
  required DOMString name;
  DOMString? _namespace = "http://www.w3.org/1999/xhtml";
};

// Used by "elements"
dictionary SanitizerElementNamespaceWithAttributes : SanitizerElementNamespace {
  sequence<SanitizerAttribute> attributes;
  sequence<SanitizerAttribute> removeAttributes;
};

typedef (DOMString or SanitizerElementNamespace) SanitizerElement;
typedef (DOMString or SanitizerElementNamespaceWithAttributes) SanitizerElementWithAttributes;

dictionary SanitizerAttributeNamespace {
  required DOMString name;
  DOMString? _namespace = null;
};
typedef (DOMString or SanitizerAttributeNamespace) SanitizerAttribute;

dictionary SanitizerConfig {
  sequence<SanitizerElementWithAttributes> elements;
  sequence<SanitizerElement> removeElements;
  sequence<SanitizerElement> replaceWithChildrenElements;

  sequence<SanitizerAttribute> attributes;
  sequence<SanitizerAttribute> removeAttributes;

  boolean comments;
  boolean dataAttributes;
};