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. Assertconfigurationvalidである。

  3. elementを、canonicalize a sanitizer elementelementとともに実行した結果に設定する。

  4. もしelement["name"] が"html"と一致し、 element["namespace"] が一致し、 HTML namespaceである場合:

    1. falseを返す。

  5. もしconfiguration["replaceWithChildrenElements"] がelement含む場合:

    1. falseを返す。

  6. Removeを用いて、 configuration["removeElements"]からelementを削除する。

  7. Removeを用いて、 configuration["elements"] リストからelementを削除する。

  8. Add を用いてelementconfiguration["replaceWithChildrenElements"]に追加する。

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

注: 渡される構成がすでに canonicalize the configuration を実行済みであることを想定しています。 このアルゴリズムが保証すべき条件を単にアサートします。

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

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

  3. Assert: config["attributes"] が存在する、または config["removeAttributes"] が存在する

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

  5. Assert: config 内のすべての SanitizerElementNamespaceWithAttributesSanitizerElementNamespace、 および SanitizerAttributeNamespace 項目が標準化済みであること、つまりconfigcanonicalize a sanitizer element または canonicalize a sanitizer attribute を実行済みであること。

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

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

  7. それ以外の場合:

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

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

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

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

  10. それ以外の場合:

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

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

    1. もし configuration["replaceWithChildrenElements"] «[ "name" → "html", "namespace" → HTML namespace ]» を含む場合、falseを返す。

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

      1. もし intersectionconfig["elements"] と config["replaceWithChildrenElements"] で取り、その結果が empty でない場合、 falseを返す。

    3. それ以外の場合:

      1. もし intersectionconfig["removeElements"] と config["replaceWithChildrenElements"] で取り、その結果が empty でない場合、 falseを返す。

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

    1. Assert: config["dataAttributes"] が存在

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

      1. elementconfig["elements"] から取り出す:

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

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

        3. もし intersectionconfig["attributes"] と element["attributes"] with default « » から取った結果が empty でない場合、falseを返す。

        4. もし element["removeAttributes"] with default « » が subset でない場合、 config["attributes"]の falseを返す。

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

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

  13. それ以外の場合:

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

      1. elementconfig["elements"] から取り出す:

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

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

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

        4. もし intersectionconfig["removeAttributes"] と element["attributes"] with default « » から取った結果が empty でない場合、falseを返す。

        5. もし intersectionconfig["removeAttributes"] と element["removeAttributes"] with default « » から取った結果が empty でない場合、falseを返す。

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

  14. trueを返す。

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. アサートsanitizerSpecSanitizer インスタンス、 文字列SanitizerPresets のメンバー、または 辞書のいずれかである。

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

    1. アサートsanitizerSpec "default" である。

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

  5. アサートsanitizerSpecSanitizer インスタンス、 または 辞書である。

  6. もし sanitizerSpec辞書である場合:

    1. sanitizer に新しい Sanitizer インスタンスを割り当てる。

    2. setConfigurationResult設定をセットする の結果(sanitizerSpecsafe否定sanitizer 上で)を格納する。

    3. もし setConfigurationResult が false なら、 throw(例外を投げる) TypeError を行う。

    4. sanitizerSpecsanitizer を設定する。

  7. アサートsanitizerSpecSanitizer インスタンスである。

  8. sanitizerSpec を返す。

3.1. サニタイズ

メインの sanitize 操作として、ParentNode nodeSanitizer sanitizer、および boolean safe を使い、次の手順を実行する:
  1. configurationsanitizerconfiguration の値を格納する。

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

  3. もし safe が true なら、configurationunsafe を削除configuration へ適用した結果を設定する。

  4. sanitize core を、nodeconfiguration、および handleJavascriptNavigationUrlssafe にして呼び出す。

sanitize core操作は、 ParentNode nodeSanitizerConfig configuration、および boolean handleJavascriptNavigationUrlsを用いて、 nodeからDOMツリーを再帰的に巡回する。手順は以下の通り:
  1. childnodechildrenから取り出して:

    1. アサートchild実装する型は TextCommentElement またはDocumentTypeであること。

      注: このアルゴリズムは現在HTMLパーサー出力に対してのみ呼ばれるため、このアサーションは成立する。DocumentTypeparseHTMLparseHTMLUnsafeにのみ出現するはず。 将来このアルゴリズムが他のコンテキストで利用される場合、この前提の再検討が必要。

    2. もしchildDocumentType実装していれば、continueする。

    3. もしchildText実装していれば、continueする。

    4. もしchildComment実装していれば:

      1. もしconfiguration["comments"]がtrueでなければ、 remove childする。

    5. それ以外の場合:

      1. elementNamechildlocal namenamespaceを持つ SanitizerElementNamespaceとする。

      2. もしconfiguration["replaceWithChildrenElements"] が存在 しかつconfiguration["replaceWithChildrenElements"] elementNameを含む場合:

        1. アサートnodeDocument実装していないこと。

        2. sanitize corechildconfigurationhandleJavascriptNavigationUrlsで呼び出す。

        3. replace allchildchildrenchild内で置換する。

        4. Continueする。

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

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

          1. Remove child

          2. Continue

      4. それ以外の場合:

        1. もしconfiguration["removeElements"] elementNameを含む場合:

          1. Remove child

          2. Continue

      5. もしelementNameが«[ "name" → "template", "namespace" → HTML namespace ]»と 一致するなら、 childtemplate contentsに対して sanitize coreconfigurationhandleJavascriptNavigationUrlsで呼び出す。

      6. もしchildshadow hostであれば、 childshadow rootに対して sanitize coreconfigurationhandleJavascriptNavigationUrlsで呼び出す。

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

      8. もしconfiguration["elements"] が存在しかつ configuration["elements"] elementNameを含む場合:

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

      9. attributechildattribute listから取り出す:

        1. attrNameattributelocal namenamespaceを持つ SanitizerAttributeNamespaceとする。

        2. もしelementWithLocalAttributes["removeAttributes"] with default « »が attrNameを含む場合:

          1. Remove attribute

        3. それ以外で、configuration["attributes"] が存在する場合:

          1. もしconfiguration["attributes"]が attrNameを含まず、 elementWithLocalAttributes["attributes"] with default « »が attrNameを含まず、 かつ"data-"が code unit prefixではなく、 attributelocal namenamespacenullでないか、 configuration["dataAttributes"]がtrueでない場合:

            1. Remove attribute

        4. それ以外:

          1. もしelementWithLocalAttributes["attributes"] が存在 しかつelementWithLocalAttributes["attributes"] がattrNameを含まない場合:

            1. Remove attribute

          2. それ以外で、configuration["removeAttributes"] attrNameを含む場合:

            1. Remove attribute

        5. もしhandleJavascriptNavigationUrlsがtrueの場合:

          1. もし«[elementName, attrName]»がbuilt-in navigating URL attributes listのエントリに一致し、 かつattributejavascript: URLを含む場合、 remove attribute

          2. もしchildnamespaceMathML Namespace一致し、 attrlocal nameが "href"で、 attrnamespacenullまたは XLink namespace しかつattrjavascript: URLを含む場合、 remove attribute

          3. もしbuilt-in animating URL attributes list «[elementName, attrName]»を含み、 しかつattrvalueが "href"または"xlink:href"と一致する場合、 remove attribute

      10. sanitize corechildconfigurationhandleJavascriptNavigationUrlsで呼び出す。

注: 現在のブラウザは 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. attributevalue基本URLパーサー に渡して、 urlとする。

  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. elementcanonicalize a sanitizer elementelementに対して実行した結果に設定する。

  3. modifiedconfiguration["replaceWithChildrenElements"]からremove elementした結果に設定する。

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

    1. もしconfiguration["elements"]elementを含む場合:

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

      2. Remove elementconfiguration["elements"]から削除する。

      3. trueを返す。

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

    3. modifiedを返す。

  5. それ以外の場合:

    1. もしconfiguration["removeElements"]elementを含む場合:

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

      2. modifiedを返す。

    2. コメント: グローバル削除リストがあり、elementを含んでいない。

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

    4. trueを返す。

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

注: このメソッドはグローバル許可リストとグローバル削除リストの2つのケースを区別する。 グローバル削除リストにattributeを追加する場合、各要素ごとの許可リストや削除リストの調整を行う必要がある場合がある。 グローバル許可リストからattributeを削除する場合、ローカル削除リストからも削除する必要がある場合がある。

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

  2. attributecanonicalize a sanitizer attributeattributeに対して実行した結果に設定する。

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

    1. コメント: グローバル許可リストが存在する場合、attributeを削除する。

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

    3. コメント: 各要素ごとの許可リストや削除リストの調整。

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

      1. elementconfiguration["elements"]から取り出して:

        1. もしelement["attributes"]with default « » contains attribute:

          1. modifiedをtrueに設定。

          2. Remove attributeelement["attributes"]から削除する。

        2. もしelement["removeAttributes"]with default « » contains attribute:

          1. アサート: modifiedはtrueである。

          2. Remove attributeelement["removeAttributes"]から削除する。

    5. modifiedを返す。

  4. それ以外の場合:

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

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

    3. コメント: 各要素ごとの許可リストや削除リストの調整。

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

      1. elementconfiguration["elements"]から取り出して:

        1. もしelement["attributes"]with default « » contains attribute:

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

        2. もしelement["removeAttributes"]with default « » contains attribute:

          1. Remove attributeelement["removeAttributes"]から削除する。

    5. Append attributeconfiguration["removeAttributes"]に追加。

    6. trueを返す。

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

注: このアルゴリズムはunsafeを除去すると呼ばれるが、 規格上厳密な意味で"unsafe"という語を用いている。 つまり、ドキュメントへ挿入したときにJavaScriptが実行されるコンテンツを指す。 このメソッドはXSSの機会を減らすものである。

  1. アサート: key set of built-in safe baseline configuration«等しい» «[ "removeElements", "removeAttributes" ] »

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

  3. resultをfalseに設定。

  4. elementbuilt-in safe baseline configuration["removeElements"]から取り出して:

    1. remove an element elementconfigurationから呼び出す。

    2. 呼び出しがtrueを返した場合、resultをtrueに設定。

  5. attributebuilt-in safe baseline configuration["removeAttributes"]から取り出して:

    1. remove an attribute attributeconfigurationから呼び出す。

    2. 呼び出しがtrueを返した場合、resultをtrueに設定。

  6. attributeevent handler content attributesから取り出して:

    1. remove an attribute attributeconfigurationから呼び出す。

    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. 構成の正規化

Sanitizer設定 を正規化された形式で保持します。これは、 さまざまな処理ステップを容易にするためです。

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"] のどちらも存在しない場合、set configuration["removeElements"] を« »に設定する。

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

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

    1. elementsを« »とする。

    2. elementconfiguration["elements"] から取り出し:

      1. Append canonicalize a sanitizer element with attributeselementに対して実行した結果をelementsに追加。

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

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

    1. elementsを« »とする。

    2. elementconfiguration["removeElements"] から取り出し:

      1. Append canonicalize a sanitizer elementelementに対して実行した結果をelementsに追加。

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

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

    1. elementsを« »とする。

    2. elementconfiguration["replaceWithChildrenElements"] から取り出し:

      1. Append canonicalize a sanitizer elementelementに対して実行した結果をelementsに追加。

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

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

    1. attributesを« »とする。

    2. attributeconfiguration["attributes"] から取り出し:

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

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

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

    1. attributesを« »とする。

    2. attributeconfiguration["removeAttributes"] から取り出し:

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

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

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

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

サニタイザー要素(属性つき)の正規化SanitizerElementWithAttributes element に対して行うには:
  1. resultサニタイザー要素の正規化の結果を設定する。

  2. もし element辞書 の場合:

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

      1. attributes に « » を設定。

      2. attributeelement["attributes"] から取り出し:

        1. append サニタイザー属性の正規化 の結果を attributes に追加する。

      3. 設定 result["attributes"] = attributes

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

      1. attributes に « » を設定。

      2. attributeelement["removeAttributes"] から取り出し:

        1. append サニタイザー属性の正規化 の結果を attributes に追加する。

      3. 設定 result["removeAttributes"] = attributes

  3. もし result["attributes"] も result["removeAttributes"] いずれも存在しないなら:

    1. 設定 result["removeAttributes"] = « »。

  4. result を返す。

サニタイザー要素を標準化する SanitizerElement elementについて、 canonicalize a sanitizer nameelementとデフォルト名前空間としてHTML名前空間で実行した結果を返す。
サニタイザー属性を標準化する SanitizerAttribute attributeについて、 canonicalize a sanitizer nameattributeとデフォルト名前空間として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. 補助アルゴリズム

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

サニタイザー名listitemを含むのは、 listentryがあり、順序付きマップであって、 item["name"]がentry["name"]と一致し、 item["namespace"]がentry["namespace"]と一致する場合。
removeitemlist 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. もしlistnameを含むなら、return。

  2. Append namelistに追加する。

item itemAitemBより小さいのは:
  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"]に対して返す。

順序付き集合については、要素が同じであれば順序に関わらず同じと判断される。 順序付き集合 AB等しいのは、 A上位集合かつB上位集合の場合。
順序付きマップは、キーバリュータプルの列である。 順序付きマップの等価性は、このタプルの列を順序付き集合として比較したときに等しいこと。 順序付きマップ AB等しいのは、 順序付き集合としてのAエントリ順序付き集合としてのBエントリ等しい場合。
リスト list重複を持つのは、 いずれか itemlist中に item["name"]がentry["name"]かつ item["namespace"]がentry["namespace"]のentryが複数ある場合。
remove duplicateslist listから重複を除去するには:
  1. resultを« »とする。

  2. entrylistから取り出し、 add entryresultに追加する。

  3. resultを返す。

intersectionで2つのリスト AB に含まれるSanitizerElement集合の積集合と同じだが、 集合のエントリは 事前に標準化されている:
  1. set Aを« [] »とする。

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

  3. entryAから取り出し、 append canonicalize a sanitizer nameentryに対して実行した結果をset Aに追加する。

  4. entryBから取り出し、 append canonicalize a sanitizer nameentryに対して実行した結果をset Bに追加する。

  5. 集合の積集合set Aset Bで返す。

boolean boolnotを判定するには、 boolがtrueならfalseを返し、それ以外の場合trueを返す。
コメントはアルゴリズム中の特定のポイントに説明的なテキストを含む。

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 名前空間 }, { "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 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;
};