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 コミュニティおよびビジネスグループ についての詳細をご覧ください。

1. はじめに

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

ウェブアプリケーションは、クライアント側でHTML文字列を扱う必要がある場合が多くあります。 例えばクライアント側テンプレートソリューションの一部として、あるいはユーザー生成コンテンツのレンダリングとして等です。安全にこれを行うのは困難です。 文字列を単純に結合して ElementinnerHTML に詰め込むという安易な方法は、 予期しない方法でJavaScriptが実行されるリスクを伴います。

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

ブラウザは、コードを実行するタイミングをかなり正確に把握しています。 ユーザ空間のライブラリよりも、ブラウザ自身に任意の文字列から安全にHTMLをレンダリングする方法を教えることで、 ブラウザのパーサ実装の変更に合わせて維持・更新される可能性が高い形で、 より良い方法を提供できます。 本文書はそのためのAPIの概要を示します。

1.1. 目的

1.2. API概要

Sanitizer APIは、HTMLを含む文字列を解析してDOMツリーに変換し、 ユーザーが指定した設定に従ってそのツリーをフィルタリングする機能を提供します。 メソッドは2つの種類があります:

2. フレームワーク

2.1. Sanitizer 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アルゴリズムに TrustedHTMLthisrelevant global objecthtml、 "Element setHTMLUnsafe"、"script"を渡して呼び出すことで得る。

  2. targetを、 thistemplate 要素の場合は template contents、 それ以外の場合はthisとする。

  3. Set and filter HTMLtargetthiscompliantHTMLoptions、falseを渡して呼び出す。

ElementsetHTML(html, options)メソッドの手順は次のとおり:
  1. targetを、 thistemplate 要素の場合は template contents、 それ以外の場合はthisとする。

  2. Set and filter HTMLtargetthishtmloptions、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アルゴリズムに TrustedHTMLthisrelevant global objecthtml、 "ShadowRoot setHTMLUnsafe"、"script"を渡して呼び出すことで得る。

  2. Set and filter HTMLthisthisshadow host(コンテキスト要素)、 compliantHTMLoptions、falseを渡して呼び出す。

ShadowRootsetHTML(html, options)メソッドの手順は次のとおり:
  1. HTML の設定とフィルタ処理を、this(ターゲット)、this(コンテキスト要素)、 htmloptions、および true を使って行う。

Document インターフェイスは、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を、新しいDocumentcontent typeが"text/html")に設定する。

    注: document はブラウジングコンテキストを持たないため、スクリプトは無効化される。

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

  4. 文字列からHTMLをパースする。documentcompliantHTMLを渡す。

  5. sanitizerget a sanitizer instance from optionsoptionsとfalseで呼び出した結果にする。

  6. sanitizedocumentsanitizer、falseで呼び出す。

  7. documentを返す。

parseHTML(html, options)メソッドの手順は次のとおり:
  1. documentを、新しいDocumentcontent typeが"text/html")に設定する。

    注: document はブラウジングコンテキストを持たないため、スクリプトは無効化される。

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

  3. 文字列からHTMLをパースする。documenthtmlを渡す。

  4. sanitizerget a sanitizer instance from optionsoptionsとtrueで呼び出した結果にする。

  5. sanitizedocumentsanitizer、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」メソッドはデフォルトで制限がない。設定の利用意図は ページのライフサイクルの早い段階で1つまたは複数の設定を作成し、必要なときに再利用すること。これにより実装側で事前処理ができる。

設定オブジェクトは、設定辞書として取得できる。また、直接変更可能。

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

  // 設定の取得:
  SanitizerConfig get();

  // Sanitizerのリストやフィールドの変更:
  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);

  // スクリプトを実行するマークアップの除去
  boolean removeUnsafe();
};

Sanitizer には関連付けられたSanitizerConfig configurationがある。

constructor(configuration) メソッドの手順は次のとおり:
  1. もしconfigurationSanitizerPresets 文字列であれば、次を行う:

    1. アサート: configurationdefaultであること。

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

  2. validset a configurationconfigurationとtrueでthisで呼び出した戻り値を設定する。

  3. もしvalidがfalseなら、TypeErrorをスローする。

get() メソッドの手順は以下の通りです:
注: get() メソッドの外では、Sanitizer の要素と属性の順序は観察できません。 このメソッドの結果を明示的にソートすることで、例えば内部的に順不同セットを使用するなど、実装が最適化する機会を与えます。
  1. configthisconfiguration とする。

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

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

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

        1. element["attributes"] を 昇順でソート した結果に設定する。 element["attributes"] を attrAless than item attrB で比較する。

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

        1. element["removeAttributes"] を 昇順でソート した結果に設定する。 element["removeAttributes"] を attrAless than item attrB で比較する。

    2. config["elements"] を 昇順でソート した結果に設定する。 config["elements"] を elementAless than item elementB で比較する。

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

    1. config["removeElements"] を 昇順でソート した結果に設定する。 config["removeElements"] を elementAless than item elementB で比較する。

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

    1. config["replaceWithChildrenElements"] を 昇順でソート した結果に設定する。 config["replaceWithChildrenElements"] を elementAless than item elementB で比較する。

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

    1. config["attributes"] を 昇順でソート した結果に設定する。 config["attributes"] を attrAless than item attrB で比較する。

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

    1. config["removeAttributes"] を 昇順でソート した結果に設定する。 config["removeAttributes"] を attrAless than item attrB で比較する。

  7. config を返す。

allowElement(element) メソッドの手順は、 要素を許可するelementthisconfiguration で行うこと。
removeElement(element) メソッドの手順は、 要素を削除するelementthisconfiguration で行うこと。
replaceElementWithChildren(element) メソッドの手順は、要素をその子と置き換えるelementthisconfiguration で行うこと。
allowAttribute(attribute) メソッドの手順は、 属性を許可するattributethisconfiguration で行うこと。
removeAttribute(attribute) メソッドの手順は、 属性を削除するattributethisconfiguration で行うこと。
setComments(allow) メソッドの手順は、 コメントを設定するallowthisconfiguration で行うこと。
setDataAttributes(allow) メソッドの手順は、 data属性を設定するallowthisconfiguration で行うこと。
removeUnsafe() メソッドの手順は、 thisconfigurationunsafeを削除する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. 設定の不変条件

設定は開発者が目的に合わせて変更でき、また変更すべきである。方法としては、新たな設定辞書を一から作成する、既存のSanitizerの 設定を修正メソッドで操作する、get() で既存のSanitizer設定を辞書として取得して修正し、新たなSanitizerを作成する、などがある。

空の設定はすべてを許可する("unsafe"系メソッド、例えば setHTMLUnsafe で呼び出した場合)。"default"の設定は組み込みの安全なデフォルト設定を含む。"safe"と"unsafe"サニタイザーメソッドではデフォルトが異なる点に注意。

全ての構成辞書が有効とは限りません。有効な構成は冗長(同じ要素を二重に許可するなど)や矛盾(同じ要素を許可と除去両方に指定するなど)を避けます。

有効な構成となるために守るべき条件がいくつかあります:

elements 要素許可リストでは、特定の要素に対して属性の許可や削除も指定できる。これは [HTML] の構造を反映したものであり、 グローバル属性と、特定要素に適用されるローカル属性の両方を知っている。 グローバル属性とローカル属性は混在可能だが、特定の属性が一方のリストで許可され、他方のリストで禁止されるような曖昧な構成は基本的に無効である点に注意。

グローバル attributes グローバル removeAttributes
ローカル attributes 属性は、いずれかのリストに一致する場合に許可されます。重複は許可されません。 属性はローカル許可リストに含まれている場合のみ許可されます。 グローバル除去リストとローカル許可リスト間で重複エントリは許可されません。 グローバル除去リストは、この要素には機能しませんが、ローカル許可リストを持たない他の要素には適用される場合があります。
ローカル removeAttributes 属性はグローバル許可リストに含まれていて、ローカル除去リストに含まれていない場合に許可されます。ローカル除去リストはグローバル許可リストの部分集合でなければなりません。 属性は両方のリストに含まれていない場合にのみ許可されます。 グローバル除去リストとローカル除去リスト間で重複エントリは許可されません。

ほとんどの場合、グローバルリストと要素ごとのリスト間で重複は許可されませんが、グローバル許可リストと要素ごとの除去リストの場合は、後者が前者の部分集合である必要があるという非対称性にご注意ください。上記の表の抜粋として、重複に関する部分だけを示すと以下の通りです:

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

dataAttributes 設定により、カスタムデータ属性が許可されます。上記のルールは カスタムデータ属性にも簡単に拡張できます。dataAttributes を許可リストとみなした場合:

グローバル attributes および dataAttributes が設定されている場合
ローカル attributes すべてのカスタムデータ属性が許可されます。カスタムデータ属性がいずれかの許可リストに載っている場合は重複となるため許可されません。
ローカル removeAttributes カスタムデータ属性はローカル除去リストに載っていなければ許可されます。 カスタムデータ属性がグローバル許可リストに載っている場合は重複となるため許可されません。

これらのルールを言葉でまとめると:

SanitizerConfig config は、以下のすべての条件を満たす場合に 有効 です:
  1. configelements または removeElements キーのいずれかを持ち、両方は持たないこと。

  2. configattributes または removeAttributes キーのいずれかを持ち、両方は持たないこと。

  3. Assert: すべての SanitizerElementNamespaceWithAttributesSanitizerElementNamespace、 および SanitizerAttributeNamespace アイテムは正規化済み(canonicalize a sanitizer element または canonicalize a sanitizer attribute を実行済み)であること。

  4. config[elements]、 config[removeElements]、 config[replaceWithChildrenElements]、 config[attributes]、 または config[removeAttributes] が 存在する場合、 重複を含まないこと。

  5. 両方の config[elements] と config[replaceWithChildrenElements] が 存在する場合、 両者の共通部分でなければなりません。

  6. 両方の config[removeElements] と config[replaceWithChildrenElements] が 存在する場合、 両者の共通部分でなければなりません。

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

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

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

        1. element[attributes] および element[removeAttributes] が 存在する場合、重複を含まないこと。

        2. config[attributes] と element[attributes] デフォルト付き « » の 共通集合 である。

        3. element[removeAttributes] デフォルト付き « » は 部分集合である config[attributes] の。

        4. dataAttributes存在していて dataAttributes が true の場合:

          1. element[attributes] に カスタムデータ属性 が含まれていないこと。

    2. dataAttributes が true の場合:

      1. config[attributes] に カスタムデータ属性 が含まれていないこと。

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

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

      1. element[attributes] と element[removeAttributes] の両方が 存在してはいけません。

      2. element[attributes] および element[removeAttributes] が 存在する場合、重複を含まないこと。

      3. 共通集合config[removeAttributes] と element[attributes] デフォルト付き « » )は である。

      4. 共通集合config[removeAttributes] と element[removeAttributes] デフォルト付き « » )は である。

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

注: 設定のセットdictionaryから行う場合、多少の正規化が行われます。 特に、許可リストと除去リストの両方が存在しない場合は、空の除去リストとして解釈されます。したがって {} 自体は 有効な設定ではありませんが、 {removeElements:[],removeAttributes:[]} に正規化され、これは有効です。 この正規化ステップは、欠落した dictionary を空のものと一貫性を持たせるために選ばれました。つまり、 setHTMLUnsafe(txt)setHTMLUnsafe(txt, {sanitizer: {}}) と一貫性を持たせるためです。

3. アルゴリズム

HTMLを設定・フィルタするには、Element またはDocumentFragment であるtargetElement であるcontextElement文字列html辞書options真偽値safeを受け取る:
  1. safeがtrueで、contextElementローカル名が"script"、 かつcontextElement名前空間HTML名前空間 またはSVG名前空間である場合、returnする。

  2. sanitizerget a sanitizer instance from optionsoptionssafeを渡して得る。

  3. newChildrenHTMLフラグメントパースアルゴリズムcontextElementhtml、trueを渡して得る。

  4. fragmentを新しいDocumentFragmentノード文書contextElementノード文書)として作成する。

  5. nodenewChildrenの要素)について、 appendfragmentに追加する。

  6. sanitizefragmentsanitizersafeで実行する。

  7. Replace alltarget内をfragmentで置換する。

optionsからサニタイザーインスタンスを取得する には 辞書options真偽値safeを受け取る:

注: このアルゴリズムはSetHTMLOptionsSetHTMLUnsafeOptions 両方に対応しています。違いはデフォルトのみです。

  1. sanitizerSpecを"default"に設定する。

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

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

  3. AssertsanitizerSpecSanitizer インスタンス、文字列SanitizerPresetsメンバー)、または辞書のいずれか。

  4. もしsanitizerSpec文字列なら:

    1. AssertsanitizerSpecが"default"である。

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

  5. AssertsanitizerSpecSanitizerインスタンス、 または辞書である。

  6. もしsanitizerSpec辞書であるなら:

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

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

    3. もしsetConfigurationResultがfalseなら、throwTypeErrorを投げる。

    4. sanitizerSpecsanitizerに設定する。

  7. AssertsanitizerSpecSanitizer インスタンスである。

  8. sanitizerSpecを返す。

3.1. サニタイズ

主なsanitize 操作は、ParentNode nodeSanitizer sanitizerbooleansafeを使い、以下の手順を実行します:
  1. configurationsanitizerconfigurationの値とする。

  2. safeがtrueなら、configurationremove unsafeconfigurationに対して呼び出した結果に設定する。

  3. sanitize corenodeconfigurationhandleJavascriptNavigationUrlssafeで呼び出す。

sanitize core 操作は、 ParentNode nodeSanitizerConfig configurationboolean handleJavascriptNavigationUrlsを使い、 nodeからDOMツリーを再帰的に処理します。手順は以下の通り:
  1. childnode)について:

    1. AssertchildTextCommentElement、 またはDocumentTypeを 実装している。

      注: 現在、このアルゴリズムはHTMLパーサの出力に対してのみ呼ばれ、このアサーションは成立するはずです。DocumentType が現れるのはparseHTMLparseHTMLUnsafeのみです。 将来的に他のコンテキストで使う場合はこの前提を再検討する必要があります。

    2. childDocumentType を実装している場合は、continue

    3. childText を実装している場合は、continue

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

      1. configuration["comments"] がtrueでない場合、removechildを除去する。

    5. その他の場合:

      1. elementNamechildローカル名名前空間を持つ SanitizerElementNamespace とする。

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

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

        2. childchild 内で 全て置換する。

        3. 続ける

      3. configuration["removeElements"] が存在しconfiguration["removeElements"] elementName を含む場合:

        1. child削除する。

        2. 続ける

      4. configuration["elements"] が存在しconfiguration["elements"] が elementName を含まない場合:

        1. child削除する。

        2. 続ける

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

      6. childシャドウホストの場合、 childシャドウルート に対して configurationhandleJavascriptNavigationUrls を用いて sanitize core を呼び出す。

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

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

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

      9. attributechild属性リスト の中で:

        1. attrNameSanitizerAttributeNamespace とし、attributeローカル名名前空間 を設定する。

        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属性リスト のエントリと一致し、 attribute javascript: URL を含む 場合、削除する attribute

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

          3. もし 組み込みアニメーションURL属性リスト含む «[elementName, attrName]» かつ attr一致し "href" または "xlink:href" なら、削除する 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. urlbasic URL parserattributeを渡して得る。

  2. urlfailureなら、falseを返す。

  3. urlschemeが"javascript"かどうかを返す。

3.2. 構成を変更する

構成変更メソッドは、Sanitizer上のメソッドであり、 その構成を変更します。 これらのメソッドは有効性基準を維持します。 呼び出し元に対して、構成が変更されたかどうかを示すブール値を返します。

let s = new Sanitizer({elements: ["div"]});
s.allowElement("p"); // Returns true.
div.setHTML("<div><p>", {sanitizer: s});  // Allows `<div>` and `<p>`.
let s = new Sanitizer({elements: ["div"]});
s.removeElement("p");  // Return false, as <p> was not previously allowed.
div.setHTML("<div><p>", {sanitizer: s});  // Allows `<div>`. `<p>` is removed.
To allow an element SanitizerElementWithAttributes element with a SanitizerConfig configuration:
Note: このアルゴリズムはやや込み入っています。なぜなら要素許可リストは要素ごとの属性の許可・除去リストを指定できるためで、 これにより4つのケースを区別する必要があるからです。
  • グローバルの許可リストか除去リストのどちらを採用しているか、

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

  1. element属性付きサニタイザー要素の正規化の結果に設定する。 element を渡す。

  2. もし 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. 削除する。 element["attributes"] から全ての itemitemカスタムデータ属性の場合)。

      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"] が 含まない elementの場合:

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

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

      3. true を返す。

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

    7. current elementconfiguration["elements"] 内の item で、item[name] 一致 element[name] かつ item[namespace] 一致 element[namespace] であるものに設定する。

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

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

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

    11. true を返す。

  3. それ以外の場合:

    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 を返す。

要素を除去するには、 SanitizerElement elementSanitizerConfig configuration から除去する:
注記: このメソッドは4つの場合を区別する必要がある:
  • グローバル許可リストまたは除去リストを持つかどうか

  • それらがすでに element を含んでいるかどうか

  1. elementcanonicalize a sanitizer element の結果に設定する。

  2. modifiedremove elementconfiguration["replaceWithChildrenElements"] から除去した結果に設定する。

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

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

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

      2. remove elementconfiguration["elements"] から除去する。

      3. true を返す。

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

    3. modified を返す。

  4. それ以外の場合:

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

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

      2. modified を返す。

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

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

    4. true を返す。

Sanitizer において、要素をその子で置換する SanitizerElement elementSanitizerConfig configuration に対して行うには:
  1. element を、canonicalize a sanitizer elementelement に対して実行した結果に設定する。

  2. もし configuration["replaceWithChildrenElements"] element を含むなら:

    1. false を返す。

  3. Remove を用いて elementconfiguration["removeElements"] から除去する。

  4. Remove を用いて elementconfiguration["elements"] リストから除去する。

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

  6. true を返す。

Sanitizer において、属性を許可するために SanitizerAttribute attributeSanitizerConfig configuration に対して行うには:

Note: このメソッドは、グローバル許可リストかグローバル削除リストかの2つの場合を区別する。もしグローバル許可リストに attribute を追加するなら、妥当性基準を維持するために、要素ごとの許可/削除リストを調整する追加作業が必要となる場合がある。

  1. attribute を、canonicalize a sanitizer attributeattribute に対して実行した結果に設定する。

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

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

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

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

    4. Comment: 要素ごとの許可/削除リストを調整する。

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

      1. elementconfiguration["elements"] の中で:

        1. もし element["attributes"] デフォルト付き « » 含む attribute なら:

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

        2. 検証element["removeAttributes"] デフォルト付き « » が 含まない attribute

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

    7. true を返す。

  3. それ以外の場合:

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

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

      1. false を返す。

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

    4. true を返す。

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

Note: このメソッドはグローバル許可リストかグローバル削除リストかの2つの場合を区別する。 グローバル削除リストに attribute を追加した場合、妥当性基準を保つために要素ごとの許可・削除リストの修正が必要となることがある。 グローバル許可リストから attribute を削除する場合も、ローカル削除リストからも削除する必要がある場合がある。

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

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

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

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

      1. false を返す。

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

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

      1. elementconfiguration["elements"] の中で:

        1. もし element["removeAttributes"] デフォルト付き « » 含む attribute なら:

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

    5. 削除する。attributeconfiguration["attributes"] から。

    6. true を返す。

  3. それ以外の場合:

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

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

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

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

      1. elementconfiguration["elements"] の中で:

        1. もし element["attributes"] デフォルト付き « » 含む attribute なら:

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

        2. もし element["removeAttributes"] デフォルト付き « » 含む attribute なら:

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

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

    6. true を返す。

コメントを設定するには、boolean allowSanitizerConfig configuration に設定する:
  1. もし configuration["comments"] 存在する かつ configuration["comments"] が allow と等しいなら、false を返す。

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

  3. true を返す。

データ属性を設定するには、boolean allowSanitizerConfig configuration に設定する:
  1. もし configuration["attributes"] が 存在しないなら、false を返す。

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

  3. もし allow が true なら:

    1. 削除する。configuration["attributes"] から attrattrカスタムデータ属性の場合)。

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

      1. elementconfiguration["elements"] の中で:

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

          1. 削除する。element[attributes] から attrattrカスタムデータ属性の場合)。

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

  5. true を返す。

安全でないものを削除するには、SanitizerConfig configuration から次を行う:

Note: このアルゴリズム名は 安全でないものを削除する だが、 この仕様における「unsafe」 という用語は、 ドキュメントに挿入したときに JavaScript が実行される内容を指すことに限定して使っている。このメソッドは XSS の機会を除去する。

  1. 検証キー集合組み込み安全ベースライン設定 等しい «[ "removeElements", "removeAttributes" ] » であること。

  2. result を false に設定する。

  3. element組み込み安全ベースライン設定[removeElements] の中で:

    1. 要素を削除するelementconfiguration に対して呼び出す。

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

  4. attribute組み込み安全ベースライン設定[removeAttributes] の中で:

    1. 属性を削除するattributeconfiguration に対して呼び出す。

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

  5. attributeイベントハンドラー内容属性の中で:

    1. 属性を削除するattributeconfiguration に対して呼び出す。

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

  6. result を返す。

3.3. 構成を設定する

To 構成を設定する, given a 辞書 configuration, a ブール値 allowCommentsAndDataAttributes, and a Sanitizer sanitizer:
  1. configurationallowCommentsAndDataAttributesで正規化する。

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

  3. sanitizerconfigurationconfigurationに設定する。

  4. trueを返す。

3.4. 構成を正規化する

The Sanitizer は処理を容易にするためにconfigurationを正規化された形式で保存する。

ある elements リスト {elements: ["div"]}{elements: [{name: "div", namespace: "http://www.w3.org/1999/xhtml"}]} として保存される)。
canonicalize the configuration を行うために、 SanitizerConfig configuration と、booleanallowCommentsAndDataAttributes を用いる:

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

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

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

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

    1. elements を « » とする。

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

      1. Append として、 canonicalize a sanitizer element with attributes の結果 elementelements に追加する。

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

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

    1. elements を « » とする。

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

      1. Append として、 canonicalize a sanitizer element の結果 elementelements に追加する。

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

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

    1. elements を « » とする。

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

      1. Append として、 canonicalize a sanitizer element の結果 elementelements に追加する。

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

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

    1. attributes を « » とする。

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

      1. Append として、 canonicalize a sanitizer attribute の結果 attributeattributes に追加する。

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

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

    1. attributes を « » とする。

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

      1. Append として、 canonicalize a sanitizer attribute の結果 attributeattributes に追加する。

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

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

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

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

  2. elementdictionary である場合:

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

      1. attributes を « » に設定する。

      2. attributeelement["attributes"] の中で:

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

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

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

      1. attributes を « » に設定する。

      2. attributeelement["removeAttributes"] の中で:

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

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

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

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

  4. result を返す。

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

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

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

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

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

3.5. 補助アルゴリズム

この仕様で使用される、正規化済みelementattribute name のリストにおける要素の所属判定は、"name" と "namespace" の両方が一致するかどうかで行われる:

サニタイザー名 list は、containsitem を含むとは、 list の中に 順序付きマップ である entry が存在し、 item["name"] が 等しい entry["name"] であり、 item["namespace"] が 等しい entry["namespace"] である場合をいう。
removeitemリスト list から削除するには:
  1. removed を false に設定する。

  2. entry について list を繰り返す:

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

      1. entrylist から削除する。

      2. removed を true に設定する。

  3. removed を返す。

addnamelist に追加するには、name正規化済み であり、list順序付きマップ であること:
  1. もし listcontainsname を含むなら、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["name"] が コード単位で小さいかどうかを返す。itemB["name"]。

順序付き集合 の等価性は、そのメンバーの等価性であり、順序は問わない: 順序付き集合 ABequal である、もし Asuperset であり、かつ Bsuperset である場合。
順序付きマップ は、キータプルの列である。 順序付きマップ の等価性は、このタプル列を順序付き集合とみなしたときの等価性である。 順序付きマップ ABequal である、もし 順序付き集合 Aエントリ順序付き集合 Bエントリequal である場合。
リスト listhas duplicates であるとは、 任意の item について list の中に item["name"] と等しい entry["name"] および item["namespace"] と等しい entry["namespace"] を持つ entry が2つ以上存在する場合。
remove duplicatesリスト list から重複を取り除くには、
  1. result を « » にする。

  2. entry について list を繰り返し、addentryresult に追加する。

  3. result を返す。

intersection とは、2つの リスト A および B (どちらも SanitizerElement を含む)が 集合の積集合 と同じになるが、 集合 の各エントリは事前に 正規化 される:
  1. set A を « [] » にする

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

  3. entry について A を繰り返し、 appendcanonicalize a sanitizer name の結果を set A に追加する。

  4. entry について B を繰り返し、 appendcanonicalize a sanitizer name の結果を set B に追加する。

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

boolean boolnot を判定するには、 bool が true なら false を、そうでなければ true を返す。
Comment とは、 アルゴリズムの中の特定の箇所について説明的なテキストを含むものである。

3.6. 組み込み

組み込みは四つある:

組み込みの安全なデフォルト構成は次の通りである:

{
  "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": "rel",
          "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": "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:」によるナビゲーションが「unsafe」となるものであり、次の通りです:

«[
[ { "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" → "iframe", "namespace" → HTML 名前空間 }, { "name" → "src", "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" → "animateMotion", "namespace" → SVG 名前空間 }, { "name" → "attributeName", "namespace" → null } ],
[ { "name" → "animateTransform", "namespace" → SVG 名前空間 }, { "name" → "attributeName", "namespace" → null } ],
[ { "name" → "set", "namespace" → SVG 名前空間 }, { "name" → "attributeName", "namespace" → null } ],

4. セキュリティに関する考慮事項

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

とはいえ、Sanitizer APIの正しい使用では保護できないセキュリティ上の問題もあり、これらのシナリオは以下のセクションで説明します。

4.1. サーバーサイド反射型・保存型XSS

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

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

4.2. DOMクラッタリング

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

DOMクラッタリングとは、悪意のあるHTMLがidname属性を使って要素に名前を付けることで、DOM内の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は、文字列をノードツリーへ変換する関数のみを提供します。すべてのSanitizer関数が暗黙的にコンテキストを指定します:Element.setHTML()は現在の要素を使用し、Document.parseHTML()は新しいドキュメントを作成します。そのためSanitizer APIは直接的に変異型XSSの影響を受けません。

開発者が例えば.innerHTMLなどによってサニタイズされたノードツリーを文字列として取得し、それを再度パースする場合、変異型XSSが発生する可能性があります。このような利用は推奨されません。HTMLを文字列として処理・渡す必要がある場合でも、その文字列は信頼できないものとみなし、DOMに挿入する際は再度サニタイズする必要があります。言い換えれば、サニタイズ後に直列化したHTMLツリーはもはや「サニタイズ済み」とみなすことはできません。

mXSSのより詳しい解説は、[MXSS]に記載されています。

5. 謝辞

本仕様はcure53の[DOMPURIFY]、 Internet Explorerのwindow.toStaticHTML()、 そしてBen Buckschによる [HTMLSanitizer]に触発されています。 また、Anne van Kesteren、Krzysztof Kotowicz、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; et al. 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;
};