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 = {});
};
partial interface Element {
  [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 = {});
};
partial interface ShadowRoot {
  [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 = {});
};
partial interface Document {
  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 allowProcessingInstruction(SanitizerPI pi);
  boolean removeProcessingInstruction(SanitizerPI pi);
  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. configthis設定とする。

  2. 断言: config有効である。

  3. もし config["elements"] が存在する場合:

    1. すべての config["elements"] の element に対して:

      1. もし element["attributes"] が存在する場合:

        1. element["attributes"] を、昇順でソートする element["attributes"] の結果で設定し、attrA小さい項目として attrB と比較する。

      2. もし element["removeAttributes"] が存在する場合:

        1. element["removeAttributes"] を、昇順でソートする 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["processingInstructions"] が存在する場合:

    1. config["processingInstructions"] を、昇順でソートする config["processingInstructions"] の結果で設定し、piA["target"] が コード単位比較でより小さい piB["target"] である。

  7. その他の場合:

    1. config["removeProcessingInstructions"] を、昇順でソートする config["removeProcessingInstructions"] の結果で設定し、piA["target"] が コード単位比較でより小さい piB["target"] である。

  8. もし config["attributes"] が存在する場合:

    1. config["attributes"] を、昇順でソートする config["attributes"] の結果で設定し、attrA小さい項目として attrB と比較する。

  9. その他の場合:

    1. config["removeAttributes"] を、昇順でソートする config["removeAttributes"] の結果で設定し、attrA小さい項目として attrB と比較する。

  10. config を返す。

allowElement(element) メソッドの手順は以下のとおりです:
注記: このアルゴリズムは比較的複雑です。なぜなら、要素許可リストでは 個々の要素に対して属性の許可・除外リストを指定できるからです。これにより、以下の4つの場合を区別する必要があります:
  • グローバルな許可・除外リストがあるかどうか、

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

  1. configurationthis設定とする。

  2. 断言: configuration有効である。

  3. elementサニタイザー要素と属性を正規化する の 結果にする。

  4. もし configuration["elements"] が存在する場合:

    1. modifiedremove elementconfiguration["replaceWithChildrenElements"] から実行した結果とする。

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

    3. もし configuration["attributes"] が存在する場合:

      1. もし element["attributes"] が存在する場合:

        1. element["attributes"] を重複削除した element["attributes"] に設定する。

        2. element["attributes"] を 差集合 element["attributes"] と configuration["attributes"] の結果に設定する。

        3. もし configuration["dataAttributes"] が true の場合:

          1. すべての itemelement["attributes"] から削除する(itemカスタムデータ属性の場合)。

      2. もし element["removeAttributes"] が存在する場合:

        1. element["removeAttributes"] を重複削除した element["removeAttributes"] に設定する。

        2. element["removeAttributes"] を 共通集合 element["removeAttributes"] と configuration["attributes"] の結果に設定する。

    4. その他の場合:

      1. もし element["attributes"] が存在する場合:

        1. element["attributes"] を重複削除した 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"] を重複削除した element["removeAttributes"] に設定する。

        2. element["removeAttributes"] を 差集合 element["removeAttributes"] と configuration["removeAttributes"] の結果に設定する。

    5. もし configuration["elements"] が 含まれていない場合:

      1. コメント: これは、グローバル許可リストに element がまだ存在しない場合です。

      2. 追加 elementconfiguration["elements"] に。

      3. trueを返す。

    6. コメント: これは、グローバル許可リストにすでに element が存在する場合です。

    7. current elementconfiguration["elements"] 内で item["name"] が element["name"] と等しく、かつ item["namespace"] が element["namespace"] と等しい item とする。

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

    9. 削除 elementconfiguration["elements"] から。

    10. 追加 elementconfiguration["elements"] に。

    11. trueを返す。

  5. その他の場合:

    1. もし element["attributes"] が存在するまたは element["removeAttributes"] (デフォルト« »付き)空でない場合:

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

      2. falseを返す。

    2. modifiedremove elementconfiguration["replaceWithChildrenElements"] から実行した結果とする。

    3. もし configuration["removeElements"] が 含まれていない element の場合:

      1. コメント: これはグローバル除外リストに element が含まれていない場合です。

      2. modified を返す。

    4. コメント: これは、グローバル除外リストに element が含まれている場合です。

    5. 削除 elementconfiguration["removeElements"] から。

    6. trueを返す。

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

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

  3. elementに、サニタイザー要素を正規化するの結果(elementを用いて)を設定する。

  4. もし組み込みの置換不可要素リスト含むなら、elementを:

    1. falseを返す。

  5. もしconfiguration["replaceWithChildrenElements"] が含むなら、elementを:

    1. falseを返す。

  6. 削除elementconfiguration["removeElements"] から。

  7. 削除elementconfiguration["elements"] リストから。

  8. 追加elementconfiguration["replaceWithChildrenElements"] へ。

  9. trueを返す。

allowProcessingInstruction(pi) メソッドの手順は以下の通りです:
  1. configurationthis設定とする。

  2. 断言: configuration有効である。

  3. piサニタイザー処理命令を正規化するの結果に設定する。

  4. もし configuration["processingInstructions"] が存在する場合:

    1. もし configuration["processingInstructions"] pi を含む場合:

      1. false を返す。

    2. 追加 piconfiguration["processingInstructions"] に。

    3. true を返す。

  5. その他の場合:

    1. もし configuration["removeProcessingInstructions"] pi を含む場合:

      1. 削除 "target" が pi["target"] に等しい項目を configuration["removeProcessingInstructions"] から。

      2. true を返す。

    2. false を返す。

removeProcessingInstruction(pi) メソッドの手順は以下の通りです:
  1. configurationthis設定とする。

  2. 断言: configuration有効である。

  3. piサニタイザー処理命令を正規化するの結果に設定する。

  4. もし configuration["processingInstructions"] が存在する場合:

    1. もし configuration["processingInstructions"] pi を含む場合:

      1. 削除 "target" が pi["target"] に等しい項目を configuration["processingInstructions"] から。

      2. true を返す。

    2. false を返す。

  5. その他の場合:

    1. もし configuration["removeProcessingInstructions"] pi を含む場合:

      1. false を返す。

    2. 追加 piconfiguration["removeProcessingInstructions"] に。

    3. true を返す。

allowAttribute(attribute) メソッドの手順は以下の通りです:
注記: このメソッドは、グローバルな許可リストとグローバルな除外リストを区別します。グローバル許可リストに attribute を追加する場合、個別の要素ごとの許可リストや除外リストの整合性を維持するため追加の処理が必要になるかもしれません。
  1. configurationthis設定とする。

  2. 断言: configuration有効である。

  3. attributeサニタイザー属性を正規化する の結果に設定する。

  4. もし configuration["attributes"] が存在する場合:

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

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

    3. もし configuration["attributes"] attribute を含む場合 false を返す。

    4. コメント: 個別要素ごとに許可・除外リストの調整。

    5. もし configuration["elements"] が存在する場合:

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

        1. もし element["attributes"] (デフォルト « » 付きで) attribute を含む場合:

          1. 削除 attributeelement["attributes"] から。

        2. 断言: element["removeAttributes"] (デフォルト « » 付きで) attribute を含まない

    6. 追加 attributeconfiguration["attributes"] に。

    7. true を返す。

  5. その他の場合:

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

    2. もし configuration["removeAttributes"] attribute を含まない場合:

      1. false を返す。

    3. 削除 attributeconfiguration["removeAttributes"] から。

    4. true を返す。

removeAttribute(attribute) メソッドの手順は 属性を除去するattributethis設定 で呼び出すことである。
setComments(allow) メソッドの手順は以下の通りです:
  1. configurationthis設定とする。

  2. 断言: configuration有効である。

  3. もし configuration["comments"] が存在するかつ configuration["comments"] が allow と等しい場合、false を返す;

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

  5. true を返す。

setDataAttributes(allow) メソッドの手順は以下の通りです:
  1. configurationthis設定とする。

  2. 断言: configuration有効である。

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

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

  5. もし allow が true の場合:

    1. 削除 configuration["attributes"] から attrカスタムデータ属性 であるすべての項目を。

    2. もし configuration["elements"] が存在する場合:

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

        1. もし element["attributes"] が存在する場合:

          1. 削除 element["attributes"] から attrカスタムデータ属性 であるすべての項目を。

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

  7. true を返す。

removeUnsafe() メソッドの手順は、 this設定安全でないものを除去するthis設定 で呼び出した結果で更新することである。

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 SanitizerProcessingInstruction {
  required DOMString target;
};

typedef (DOMString or SanitizerProcessingInstruction) SanitizerPI;

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<SanitizerPI> processingInstructions;
  sequence<SanitizerPI> removeProcessingInstructions;

  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有効 かどうかを判定するには:

注記: 渡される設定は事前に 設定の正規化手順を実行されていることが想定されています。 ここではそのアルゴリズムで保証された条件を単に断言するだけです。

  1. 断言: config["elements"] が存在する、または config["removeElements"] が存在する。

  2. もし config["elements"] が存在し、かつ config["removeElements"] が存在する場合、falseを返す。

  3. 断言: config["processingInstructions"] が存在する、または config["removeProcessingInstructions"] が存在する。

  4. もし config["processingInstructions"] が存在し、かつ config["removeProcessingInstructions"] が存在する場合、falseを返す。

  5. 断言: config["attributes"] が存在する、または config["removeAttributes"] が存在する。

  6. もし config["attributes"] が存在し、かつ config["removeAttributes"] が存在する場合、falseを返す。

  7. 断言: すべての SanitizerElementNamespaceWithAttributesSanitizerElementNamespaceSanitizerProcessingInstruction、 および SanitizerAttributeNamespace 項目は正規化済みでなければならない(該当する 要素の正規化処理命令の正規化 または 属性の正規化 を経ている)。

  8. もし config["elements"] が存在する場合:

    1. もし config["elements"] 重複がある場合、falseを返す。

  9. その他の場合:

    1. もし config["removeElements"] 重複がある場合、falseを返す。

  10. もし config["replaceWithChildrenElements"] が存在かつ 重複がある場合、falseを返す。

  11. もし config["processingInstructions"] が存在する場合:

    1. もし config["processingInstructions"] targetが重複している場合、falseを返す。

  12. その他の場合:

    1. もし config["removeProcessingInstructions"] targetが重複している場合、falseを返す。

  13. もし config["attributes"] が存在する場合:

    1. もし config["attributes"] 重複がある場合、falseを返す。

  14. その他の場合:

    1. もし config["removeAttributes"] 重複がある場合、falseを返す。

  15. もし config["replaceWithChildrenElements"] が存在する場合:

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

      1. 組み込み非置換要素リスト element を含む場合、falseを返す。

    2. もし config["elements"] が存在する場合:

      1. config["elements"] と config["replaceWithChildrenElements"] の 共通部分(intersection)空でない場合、falseを返す。

    3. その他の場合:

      1. config["removeElements"] と config["replaceWithChildrenElements"] の 共通部分(intersection)空でない場合、falseを返す。

  16. もし config["attributes"] が存在する場合:

    1. 断言: config["dataAttributes"] が存在する。

    2. もし config["elements"] が存在する場合:

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

        1. もし element["attributes"] が存在 かつ element["attributes"] 重複がある 場合、falseを返す。

        2. もし element["removeAttributes"] が存在かつ element["removeAttributes"] 重複がある 場合、falseを返す。

        3. もし config["attributes"] と element["attributes"] (デフォルト« »付き)共通部分が空でない場合、falseを返す。

        4. もし element["removeAttributes"] (デフォルト« »付き)config["attributes"]の部分集合でない場合、 falseを返す。

        5. もし config["dataAttributes"] が true かつ element["attributes"] が カスタムデータ属性 を含む場合、falseを返す。

    3. config["dataAttributes"] が true かつ config["attributes"] が カスタムデータ属性 を含む場合、 falseを返す。

  17. その他の場合:

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

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

        1. element["attributes"] が存在 かつ element["removeAttributes"] が存在する場合、falseを返す。

        2. もし element["attributes"] が存在 かつ element["attributes"] 重複がある場合、falseを返す。

        3. もし element["removeAttributes"] が存在 かつ element["removeAttributes"] 重複がある場合、falseを返す。

        4. もし config["removeAttributes"] と element["attributes"] (デフォルト« »付き)共通部分が空でない場合、falseを返す。

        5. もし config["removeAttributes"] と element["removeAttributes"] (デフォルト« »付き)共通部分が空でない場合、falseを返す。

    2. config["dataAttributes"] が存在する場合、falseを返す。

  18. trueを返す。

注記: 設定をセットする際、 ディクショナリからの場合は 正規化されます。特に、allow-listとremove-listが両方とも省略されている場合は、 空のremove-listとして扱われます。したがって {} 自体は 有効 な設定ではありませんが、 正規化により {removeElements:[],removeAttributes:[]} となり有効となります。この正規化処理は、 ディクショナリが省略された場合と空の場合を同じとするために選択されました。 すなわち 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 で置き換える

オプションからサニタイザーインスタンスを取得するには、 ディクショナリ options真偽値 safe を用いる:

注記: このアルゴリズムは SetHTMLOptionsSetHTMLUnsafeOptions の両方に対応しており、デフォルト値のみが異なります。

  1. sanitizerSpec を "default" にする。

  2. もし options["sanitizer"] が存在する場合:

    1. sanitizerSpecoptions["sanitizer"] の値をセットする。

  3. 断言: sanitizerSpecSanitizer インスタンス・ SanitizerPresetsメンバーの文字列 または ディクショナリ のいずれかである。

  4. もし sanitizerSpec文字列 である場合:

    1. 断言: sanitizerSpec "default" である。

    2. sanitizerSpec組み込みの安全なデフォルト設定 をセットする。

  5. 断言: sanitizerSpecSanitizer インスタンスまたは ディクショナリ である。

  6. もし sanitizerSpecディクショナリ である場合:

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

    2. setConfigurationResultset a configurationsanitizerSpecnot safesanitizer に対して呼び出した結果とする。

    3. もし setConfigurationResult が false の場合、例外を投げる TypeError

    4. sanitizerSpecsanitizer をセットする。

  7. 断言: sanitizerSpecSanitizer インスタンスである。

  8. sanitizerSpec を返す。

3.1. サニタイズ

メインの sanitize 操作は、ParentNode nodeSanitizer sanitizer、および boolean safe を用いて、次のステップを実行する:
  1. configurationsanitizer設定の値とする。

  2. 断言configuration有効である。

  3. もし safe が true ならば、configurationremove unsafeconfiguration に 実行した結果に設定する。

  4. sanitize corenodeconfiguration、および handleJavascriptNavigationUrlssafe に設定して呼び出す。

sanitize core 操作は、 ParentNode nodeSanitizerConfig configuration、および boolean handleJavascriptNavigationUrls を用いて nodeから始まるDOMツリーを再帰的に処理する。ステップは次の通り:
  1. node child について:

    1. 断言: childTextCommentElementProcessingInstruction または DocumentType を実装している。

      注記: 現在、このアルゴリズムはHTMLパーサの出力でのみ呼び出され、この断言は常に成り立つ。 DocumentType が現れるのは parseHTML または parseHTMLUnsafe のみ。今後アルゴリズムが他文脈で使われる場合は要再検討。

    2. もし childDocumentType を実装しているなら、次へ

    3. もし childText を実装しているなら、次へ

    4. もし childComment を実装している場合:

      1. configuration["comments"] が true でなければ、 child を削除する。

    5. もし childProcessingInstruction を実装している場合:

      1. piTargetchildtargetとする。

      2. configuration["processingInstructions"] が存在する場合:

        1. configuration["processingInstructions"] が piTarget を含まない場合:

          1. child を削除

      3. その他の場合:

        1. configuration["removeProcessingInstructions"] が piTargetを含む場合:

          1. child を削除

    6. その他の場合:

      1. elementName を、childローカル名および 名前空間を持つ SanitizerElementNamespace とする。

      2. configuration["replaceWithChildrenElements"] が存在する、 かつ configuration["replaceWithChildrenElements"] が elementName含む場合:

        1. 表明するnodeDocument実装しない。

        2. child に対し、configuration および handleJavascriptNavigationUrls を伴って sanitize core を呼び出す。

        3. fragment を、ノード文書nodeノード文書である、新しい DocumentFragment とする。

        4. childである 各 innerChild について反復しinnerChildfragment追加する。

        5. node 内で childfragment置換する。

          注: ここで置換は投げないはずである。 なぜなら、そのアルゴリズムが成功裏に実行されるための構造上の 事前条件が満たされているはずだからである。

        6. 続行する

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

        1. configuration["elements"] が elementName含まない 場合:

          1. child削除する。

          2. 続行する

      4. そうでない場合:

        1. configuration["removeElements"] が elementName含む 場合:

          1. child削除する。

          2. 続行する

      5. elementName が «[ "name" → "template", "namespace" → HTML 名前空間 ]» と等しい場合、 childtemplate contentsに対し、 configuration および handleJavascriptNavigationUrls を伴って sanitize core を呼び出す。

      6. childシャドウホストである場合、 childシャドウルートに対し、 configuration および handleJavascriptNavigationUrls を伴って sanitize core を呼び出す。

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

      8. configuration["elements"] が存在する、かつ configuration["elements"] が elementName含む 場合:

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

      9. child属性リスト内の 各 attribute について反復する

        1. attrName を、attributeローカル名および 名前空間を持つ SanitizerAttributeNamespace とする。

        2. elementWithLocalAttributes["removeAttributes"] が、« » を既定値として attrName含む 場合:

          1. attribute削除する。

        3. そうでなく、configuration["attributes"] が存在する場合:

          1. configuration["attributes"] が attrName含まず、かつ elementWithLocalAttributes["attributes"] が、« » を既定値として attrName含まず、かつ "data-" が attributeローカル名符号単位接頭辞でなく、かつ 名前空間null でない、または configuration["dataAttributes"] が true でない場合:

            1. attribute削除する。

        4. そうでない場合:

          1. elementWithLocalAttributes["attributes"] が存在する、かつ elementWithLocalAttributes["attributes"] が attrName含まない 場合:

            1. attribute削除する。

          2. そうでなく、configuration["removeAttributes"] が attrName含む 場合:

            1. attribute削除する。

        5. handleJavascriptNavigationUrls の場合:

          1. «[elementName, attrName]» が 組み込みの ナビゲーション URL 属性リスト内の項目に一致し、かつ attributejavascript: URL を 含む場合、attribute削除する。

          2. child名前空間MathML 名前空間あり、かつ attrローカル名が "href" であり、かつ attr名前空間null である、または XLink 名前空間であり、かつ attrjavascript: URL を 含む場合、 attribute削除する。

          3. 組み込みの アニメーション URL 属性リスト が «[elementName, attrName]» を含み、かつ attrが "href" または "xlink:href" である場合、attribute削除する。

      10. child に対し、 configuration および handleJavascriptNavigationUrls を伴って sanitize core を呼び出す。

注記: 現在のブラウザは javascript: URL を ナビゲーション時のみサポートしている。ナビゲーション自体は XSS 脅威でないため javascript: へのナビゲーションのみ処理し、その他のナビゲーションは一般化しない。

宣言的ナビゲーションには主に次のカテゴリがある:

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

  2. フォーム送信時のアクションによりナビゲーションされるフォーム要素

  3. [MathML] では 任意の要素をアンカーとして扱える

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

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

MathML の場合はこの仕様で正式に「名前空間ごとのグローバル」ルールがないため、個別ルールでカバーされる。

SVGアニメーションの場合は 組み込みアニメーションURL属性リストでカバーされる。 ただしSVGアニメーション要素の意味合いはアニメーション対象に依存し、サニタイズ実行時に最終対象が分からないため、 sanitize アルゴリズムは href 属性のアニメーションを常にブロックする。

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

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

  3. urlスキーム が "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サニタイザー要素の正規化の結果に設定する。

  3. modifiedremoveconfiguration["replaceWithChildrenElements"] から element を削除した結果に設定する。

  4. もし configuration["elements"] が存在する場合:

    1. もし configuration["elements"] element が含まれる場合:

      1. コメント: グローバル許可リストがあり、そこに element が含まれている。

      2. removeconfiguration["elements"] から element を削除する。

      3. true を返す。

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

    3. modified を返す。

  5. その他の場合:

    1. もし configuration["removeElements"] element が含まれる場合:

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

      2. modified を返す。

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

    3. addconfiguration["removeElements"] に element を追加する。

    4. true を返す。

属性を削除するには SanitizerAttributeattributeSanitizerConfig configuration から削除する:

注記: このメソッドは2つの場合、つまりグローバル許可リストか、グローバル除外リストか、を区別します。 グローバル除外リストに attribute を追加するなら、妥当性基準を維持するため追加の処理が必要かもしれません。 グローバル許可リストから attribute を削除する場合も、ローカル除外リストからも削除が必要なことがあります。

  1. 断言: configuration有効である。

  2. attributeサニタイザー属性の正規化の結果に設定する。

  3. もし configuration["attributes"] が存在する場合:

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

    2. modifiedremoveconfiguration["attributes"] から attribute を削除した結果に設定する。

    3. コメント: 各要素ごとの許可・除外リストを修正する。

    4. もし configuration["elements"] が存在する場合:

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

        1. もし element["attributes"] (デフォルト« »付き) attributeが含まれる場合:

          1. modified を true に設定する。

          2. removeelement["attributes"] から attribute を削除。

        2. もし element["removeAttributes"] (デフォルト« »付き) attributeが含まれる場合:

          1. 断言: modified は true。

          2. removeelement["removeAttributes"] から attribute を削除。

    5. modified を返す。

  4. その他の場合:

    1. コメント: グローバル除外リストの場合、attributeを追加する。

    2. もし configuration["removeAttributes"] attribute を含む場合、 falseを返す。

    3. コメント: 各要素ごとの許可・除外リストを修正する。

    4. もし configuration["elements"] が存在する場合:

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

        1. もし element["attributes"] (デフォルト« »付き) attributeが含まれる場合:

          1. removeelement["attributes"] から attribute を削除。

        2. もし element["removeAttributes"] (デフォルト« »付き) attributeが含まれる場合:

          1. removeelement["removeAttributes"] から attribute を削除。

    5. appendattributeconfiguration["removeAttributes"] に追加する。

    6. true を返す。

unsafeを除去するには、 SanitizerConfig configuration に対して、次を実行する:

注記: このアルゴリズムは remove unsafe と呼ばれているが、 この仕様での「unsafe」は厳密には、 ドキュメント挿入時に JavaScript が実行される内容のみを指します。 つまり、このメソッドはXSSの機会を除去します。

  1. アサートbuilt-in safe baseline configurationキーセット次と等しい: « [ "removeElements", "removeAttributes" ] ».

  2. 断言: configuration有効である。

  3. result を false にする。

  4. element組み込み安全ベースライン構成["removeElements"] の 要素について:

    1. 要素を削除するelementconfiguration から削除する。

    2. 呼び出し結果が true なら result を true にする。

  5. attribute組み込み安全ベースライン構成["removeAttributes"] の属性について:

    1. 属性を削除するattributeconfiguration から削除する。

    2. 呼び出し結果が true なら result を true にする。

  6. attributeイベントハンドラーコンテンツ属性で:

    1. 属性を削除するattributeconfiguration から削除する。

    2. 呼び出し結果が true なら result を true にする。

  7. result を返す。

3.3. 構成を設定する

設定をセットするには、ディクショナリ configuration真偽値 allowCommentsPIsAndDataAttributesSanitizer sanitizer が与えられたとき:
  1. 正規化 configurationallowCommentsPIsAndDataAttributes とともに行う。

  2. もし configuration有効 でなければ、false を返す。

  3. sanitizer設定configuration にセットする。

  4. trueを返す。

3.4. 構成の正規化

Sanitizerは、設定を正規化された形式で格納します。これは、複数の処理手順を簡略化するためです。

elements リスト {elements: ["div"]}{elements: [{name: "div", namespace: "http://www.w3.org/1999/xhtml"}] のように格納されます。
SanitizerConfig configuration を、ブール値 allowCommentsPIsAndDataAttributes構成を正規化するには:

注: configuration は、JavaScript 値を SanitizerConfig に変換した [WebIDL] の結果であると仮定する。

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

  2. configuration["processingInstructions"] も configuration["removeProcessingInstructions"] も存在しない場合:

    1. allowCommentsPIsAndDataAttributes が true の場合、configuration["removeProcessingInstructions"] を « » に設定する

    2. そうでない場合、configuration["processingInstructions"] を « » に設定する

  3. configuration["attributes"] も configuration["removeAttributes"] も存在しない場合、configuration["removeAttributes"] を « » に設定する

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

    1. elements を « » とする。

    2. configuration["elements"] の各 element について反復し、次を行う:

      1. element について属性付き sanitizer 要素を正規化する結果を elements追加する

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

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

    1. elements を « » とする。

    2. configuration["removeElements"] の各 element について反復し、次を行う:

      1. element についてsanitizer 要素を正規化する結果を elements追加する

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

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

    1. elements を « » とする。

    2. configuration["replaceWithChildrenElements"] の各 element について反復し、次を行う:

      1. element についてsanitizer 要素を正規化する結果を elements追加する

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

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

    1. processingInstructions を « » とする。

    2. configuration["processingInstructions"] の各 pi について反復する

      1. pi についてsanitizer 処理命令を正規化する結果を processingInstructions追加する

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

  8. configuration["removeProcessingInstructions"] が存在する場合:

    1. processingInstructions を « » とする。

    2. configuration["removeProcessingInstructions"] の各 pi について反復する

      1. pi についてsanitizer 処理命令を正規化する結果を processingInstructions追加する

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

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

    1. attributes を « » とする。

    2. configuration["attributes"] の各 attribute について反復し、次を行う:

      1. attribute についてsanitizer 属性を正規化する結果を attributes追加する

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

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

    1. attributes を « » とする。

    2. configuration["removeAttributes"] の各 attribute について反復し、次を行う:

      1. attribute についてsanitizer 属性を正規化する結果を attributes追加する

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

  11. configuration["comments"] が存在しない場合、configuration["comments"] を allowCommentsPIsAndDataAttributes設定する

  12. configuration["attributes"] が存在し、かつ configuration["dataAttributes"] が存在しない場合、 configuration["dataAttributes"] を allowCommentsPIsAndDataAttributes設定する

SanitizerElementWithAttributes element属性付き sanitizer 要素を 正規化するには:
  1. result を、elementsanitizer 要素を正規化する結果とする。

  2. element辞書である場合:

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

      1. attributes を « » とする。

      2. element["attributes"] の各 attribute について反復する

        1. attributesanitizer 属性を正規化する結果を attributes追加する

      3. result["attributes"] を attributes設定する

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

      1. attributes を « » とする。

      2. element["removeAttributes"] の各 attribute について反復する

        1. attributesanitizer 属性を正規化する結果を attributes追加する

      3. result["removeAttributes"] を attributes設定する

  3. result["attributes"] も result["removeAttributes"] も存在しない場合:

    1. result["removeAttributes"] を « » に設定する

  4. result を返す。

サニタイザー要素を正規化するには、 SanitizerElement elementサニタイザー名を正規化する を使い、 elementとデフォルト名前空間「HTML namespace」を渡し、その結果を返す。
サニタイザー処理命令を正規化するには pi について次を実行する:
  1. 断言: piDOMString または ディクショナリである。

  2. もし piDOMString なら «[ "target" → pi ]» を返す。

  3. 断言: piディクショナリ であり pi["target"] が存在する

  4. «[ "target" → pi["target"] ]» を返す。

サニタイザー属性を正規化するには、 SanitizerAttribute attributeについて、サニタイザー名を正規化する を使い、 attributeとデフォルト名前空間nullを渡して、その結果を返す。
サニタイザー名を正規化するには name とデフォルト名前空間 defaultNamespace を使い、次の手順を実行する:
  1. 断言: nameDOMString または ディクショナリである。

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

  3. 断言: nameディクショナリ かつ、name["name"] および name["namespace"] が存在する

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

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

3.5. 補助アルゴリズム

サニタイザー名 listcontains item となるのは、 list の中に 順序付きマップentry が存在し、 かつ item["name"] が entry["name"] に等しく item["namespace"] が entry["namespace"] に等しいとき。
サニタイザーターゲット listcontains a target target となるのは、 list の中に 順序付きマップentry が存在し、 target が等しい entry["target"] であるとき。
removeitemリスト list から削除する処理:
  1. removed を false にする。

  2. entrylist で繰り返し:

    1. もし item["name"] が等しく entry["name"] かつ item["namespace"] が等しい entry["namespace"] なら:

      1. entrylist から削除する。

      2. removed を true に。

  3. removed を返す。

addnamelist に追加する処理であり、 name正規化済みで、list順序付きマップ
  1. もし listcontains name なら、return。

  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"] かどうかを返す。

順序付きセットの等価性は、メンバーの一致であり順序は問わない: 順序付きセット A および Bequal であるのは、 Asuperset かつ Bsuperset であるとき。
順序付きマップキータプルの並びである。 順序付きマップの等価性は そのタプル列を順序付きセットとして扱ったセットの等価性である。 順序付きマップ A および Bequal となるのは、 順序付きセット としての Aエントリ集合と 順序付きセットとしての Bエントリ集合が equal のとき。
リスト list重複を持つ。 これは、list の任意の item について反復したとき、 list 内に、item["name"] が entry["name"] であり、かつ item["namespace"] が entry["namespace"] である entry が 複数存在する場合である。
リスト list重複するターゲットを持つ。 これは、list の任意の item について反復したとき、 list 内に、 item["target"] が entry["target"] である entry が 複数存在する場合である。
リスト list から重複を削除するには、
  1. result を « » とする。

  2. list の各 entry について反復しentryresult追加する

  3. result を返す。

SanitizerElement を含む 2 つのリスト AB積集合は、集合の積集合と同じである。 ただし、集合の項目は、あらかじめ正規化されている:
  1. set A を « [] » とする。

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

  3. A の各 entry について反復しentry について sanitizer 名を正規化する結果を set A追加する。

  4. B の各 entry について反復しentry について sanitizer 名を正規化する結果を set B追加する。

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

ブール値 bool否定を決定するには、 bool が true の場合は false を返し、そうでない場合は true を返す。
コメントは、 アルゴリズム内の特定の 点に適用される説明文を含む。

3.6. 組み込み

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

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

{
  "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
        }
      ]
    }
  ],
  "processingInstructions": [],
  "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名前空間 }, { "name" → "href", "namespace" → null } ],
[ { "name" → "area", "namespace" → HTML名前空間 }, { "name" → "href", "namespace" → null } ],
[ { "name" → "base", "namespace" → HTML名前空間 }, { "name" → "href", "namespace" → null } ],
[ { "name" → "button", "namespace" → HTML名前空間 }, { "name" → "formaction", "namespace" → null } ],
[ { "name" → "form", "namespace" → HTML名前空間 }, { "name" → "action", "namespace" → null } ],
[ { "name" → "input", "namespace" → HTML名前空間 }, { "name" → "formaction", "namespace" → null } ],
[ { "name" → "a", "namespace" → SVG名前空間 }, { "name" → "href", "namespace" → null } ],
[ { "name" → "a", "namespace" → SVG名前空間 }, { "name" → "href", "namespace" → XLink名前空間 } ],

組み込みのアニメーションURL属性リストは、 [SVG11]において ナビゲーション要素を宣言的に「javascript:」URLへ変更する用途に使うことができ、 次のようになります:

«[
[ { "name" → "animate", "namespace" → SVG名前空間 }, { "name" → "attributeName", "namespace" → null] } ],
[ { "name" → "animateTransform", "namespace" → SVG名前空間 }, { "name" → "attributeName", "namespace" → null } ],
[ { "name" → "set", "namespace" → SVG名前空間 }, { "name" → "attributeName", "namespace" → null } ],

組み込みの置換不可要素リストには、 子要素への置換を許可すると再パース問題や無効なノードツリーになる可能性があるため絶対に置換してはいけない要素が含まれます。

«[
{ "name" → "html", "namespace" → HTML名前空間 },
{ "name" → "svg", "namespace" → SVG名前空間 },
{ "name" → "math", "namespace" → MathML名前空間 },

注:

これらの制限だけでは、例えば次のようなすべての再パース攻撃を防ぐには不十分です:

// BAD EXAMPLE(悪い例)
let sanitizer = { replaceWithChildrenElements: ["tr"] };
div.setHTML("<table><tbody><tr><td><div>", { sanitizer });

div.innerHTML = div.innerHTML;
// div.innerHTML は現在 `<div></div><table><tbody><tr></tr></tbody></table>`

しかし、この例の <iframe> については再パースされて通常のHTML iframeとして有効になってしまうことは防げます:

let sanitizer = { replaceWithChildrenElements: [
    { name: "svg", namespace: "http://www.w3.org/2000/svg"}
  ]
};
div.setHTML(`<svg><iframe src="https://example.com"></iframe></svg>`, { sanitizer }); // 例外発生

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 索引

partial interface Element {
  [CEReactions] undefined setHTML(DOMString html, optional SetHTMLOptions options = {});
};

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

partial interface Document {
  static Document parseHTML(DOMString html, optional SetHTMLOptions options = {});
};

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 allowProcessingInstruction(SanitizerPI pi);
  boolean removeProcessingInstruction(SanitizerPI pi);
  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 SanitizerProcessingInstruction {
  required DOMString target;
};

typedef (DOMString or SanitizerProcessingInstruction) SanitizerPI;

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<SanitizerPI> processingInstructions;
  sequence<SanitizerPI> removeProcessingInstructions;

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

  boolean comments;
  boolean dataAttributes;
};