藤本  結衣

藤本 結衣

1654491660

組み込みのブラウザHTMLサニタイズについて知っておくべきこと

アプリケーションのセキュリティは、すべてのWebアプリケーションにとって重要な要素です。Web開発者は、脆弱性防止技術の実装など、さまざまな戦略を使用してWebアプリケーションのセキュリティ層を改善します。

通常、生のHTMLの処理を開始し、信頼できないコンテンツでDOMを操作すると、Webアプリケーションのセキュリティリスクが高まります。サードパーティのソースから直接HTMLをレンダリングしていて、そのソースがインターネットベースの脅威の影響を受ける場合、攻撃者はユーザーの同意なしにアプリケーションユーザーのコンピューターでJavaScriptコードを実行する可能性があります。これらのセキュリティ攻撃は、XSS(クロスサイトスクリプティング)攻撃として知られています。

HTMLサニタイズは、WebアプリケーションのXSS脆弱性を防ぐためにOWASPが推奨する戦略です。HTMLサニタイズは、信頼できない生のHTML文字列から安全でない(そして潜在的に悪意のある)コンテンツをユーザーに提示する前に削除するセキュリティメカニズムを提供します。

実験的な組み込みのブラウザSanitizationAPIは、信頼できないHTML文字列を安全な方法でWebアプリケーションのDOMに挿入するのに役立ちます。

HTMLサニタイズとは何ですか?

HTMLサニタイズとは、一般に、潜在的に悪意のあるJavaScriptコンテンツを生のHTML文字列から削除することを指します。2つの異なるHTMLサニタイズ実装があります。

  • クライアント側のサニタイズ:DOMレベルからの安全でないコンテンツを防止します
  • サーバー側のサニタイズ:悪意のあるHTMLコンテンツがデータベースに保存されるのを防ぎます

XSSの脆弱性を防ぐために、実際には両方のサニタイズレイヤーを使用する必要があります。データベースが悪意のあるXSSペイロードの影響を受ける場合、クライアント側のサニタイズレイヤーはすべてのアプリケーションユーザーを保護しますが、攻撃者が悪意のあるHTMLをRESTful APIから直接送信する場合、サーバー側のサニタイズはシステムを保護します。

Web開発者は、クライアント側/DOMレベルのサニタイズに次のライブラリを使用する傾向があります。

  • DOMPurity:JavaScript用のHTMLサニタイザーライブラリ
    • jsdomパッケージを介してサーバー側のNode.jsでも機能します
  • js-xss:ブラウザー、サーバー側のNode.jsで、コマンドラインツールとして機能するHTMLサニタイザーライブラリ
  • sanitize-html:Node.jsおよびブラウザー用のhtmlparser2ベースのサニタイザーライブラリ。特にReact用のラッパーライブラリがあるため、React開発者の間で非常に人気があります。

これらのライブラリは通常、ブラウザに組み込まれているDOMイテレータ、またはを使用する前に安全でないHTMLコンテンツを除外するカスタムHTMLパーサーのいずれかを使用して、安全でないHTMLを解析しますinnerHTML

ブラウザネイティブのサニタイズAPIが必要なのはなぜですか?

HTMLサニタイズAPIは、安全でないHTML文字列またはドキュメントをWebページに安全に追加するのに役立つブラウザ機能です。これは、既存のDOM要素をサニタイズし、生のHTML文字列から新しいサニタイズされたDOM要素を取得するためのメソッドを提供します。

上記のソリューションは、XSS攻撃を防ぐための非常に優れたセキュリティソリューションを提供しますが、それでもいくつかの問題があります。これらのライブラリは、ブラウザの標準が変更されたときに、サニタイズ仕様を最新の状態に保つ必要があります。たとえば、標準のHTML仕様で安全でない可能性のあるHTML属性が導入された場合、これらのライブラリのサニタイズ戦略は不安定になります。

 

ライブラリベースのサニタイズも遅くなる可能性があります。これは、安全なHTMLをWebページに挿入するときに、解析が2回(最初はライブラリのサニゼーションプロセス中に、もう1つはブラウザのDOM解析プロセス中に)行われるためです。

主な目標

HTML Sanitization APIの目標は、次の機能を介してDOMレベルのXSS攻撃を軽減することです。

  • 開発者向けに、完全な機能を備えた、完全で安定したネイティブサニタイズインターフェイスを提供します
  • 最新の標準HTML仕様をマッピングすることにより、最新のサニタイズ定義を維持します
  • 前述のサニタイズライブラリとは異なり、サニタイズされた生のHTML文字列を提供するのではなくDOMを保護する

ネイティブサニタイズの大きな魅力は、サニタイズルールに基づいてDOMを直接解析および操作するsetHTML関数を提供することです。

HTMLサニタイザーAPI仕様を理解する

サニタイザーAPIの背景、機能、現在の開発状況がわかったところで、JavaScript環境に公開されるAPI仕様を見てみましょう。

SanitizerSanitizer APIには、クラスとElement.setHTMLメソッドの2つの主要な開発者インターフェースが付属しています。

Sanitizerクラスと構成

このクラスは、サニタイズ要件に対応Sanitizerする新しいHTMLオブジェクトを作成するのに役立ちます。sanitizer次の構文が付属しています。

new Sanitizer()
new Sanitizer(config)

パラメーター化されていないコンストラクターを使用して、次の構文とデフォルト構成で新しいサニタイザーオブジェクトを作成できます。デフォルトの構成では、Sanitizer既知のXSSの脆弱性を軽減するために、セーフリストベースの手法でオブジェクトが作成されます。

const sanitizer = new Sanitizer();

ただし、Sanitizer以下に示すように、構成オブジェクトを渡すことでオブジェクトをカスタマイズできます。

const sanitizer = new Sanitizer(config);

configurationオブジェクトには次の定義があります。APIプロポーザルはまだWebインキュベーターにあるため、この構成定義は将来変更される可能性があることに注意してください。

{
  allowElements: <string Array>,
  blockElements: <string Array>,
  dropElements: <string Array>,
  allowAttributes: <Object>,
  dropAttributes: <Object>,
  allowCustomElements: <Boolean>,
  allowComments: <Boolean>
}
  • allowElements:消毒剤に含める必要のある要素のリスト
  • blockElements:サニタイザーが子要素を保持することによって除外する必要がある要素のリスト
  • dropElementsblockElementsプロパティなどの要素を除外しますが、除外されたノードに属する子要素ツリー全体も削除します
  • allowAttributes:キー配列オブジェクトとして許可された属性
    • たとえば、すべての要素'class': ['div']の属性を許可します—アスタリスク文字()を使用して、任意のHTML要素の特定の属性を許可できますclassdiv*
  • dropAttributesallowAttributes:プロパティの反対のバージョン
  • allowCustomElements:カスタム要素を許可または禁止するブール値(デフォルトはfalse
  • allowComments:コメントを許可または禁止するブール値(デフォルトはfalse

たとえば、Sanitizer以下に示すように、カスタムオブジェクトを開始して、基本的なHTMLタグとインラインスタイルのみを許可できます。

{
  'allowElements': [
    'div',
    'span',
    'p',
    'em',
    'b'
  ],
  'allowAttributes': {
    'style': ['*']
  }
}

サニタイザーAPIメソッド:sanitizesanitizeFor,およびsetHTML

このSanitizerクラスはHTMLオブジェクトを開始するのに役立ちSanitizerますが、Webアプリケーションでサニタイザーインスタンスを使用するには、他のいくつかのメソッドを使用する必要があります。次のAPI仕様を学習した後、チュートリアルセクションでサニタイザーAPIの使用方法を説明します。

Sanitizer.sanitize方法

サニタイズ(入力)

このメソッドを使用して、sanitize既存のDOMノードにサニタイザールールを適用できます。Documentこの関数はorDocumentFragmentオブジェクトを受け入れ、サニタイズさDocumentFragmentれたものを出力として返します。

Sanitizer.sanitizeFor方法

sanitizeFor(element, input)

このメソッドを使用して、安全でないHTML文字列を送信することにより、サニタイズされた要素ノードを取得できます。つまり、サニタイズルールに従って文字列elementを解析した後、タイプDOMノードを返します。input

Element.setHTML方法

setHTML(input, sanitizer)

このメソッドは、Element.innerHTMLプロパティのより安全でより設定されたバージョンです。このinnerHTMLプロパティは任意のHTML文字列を許可し、XSSペイロードの傾向があります。したがって、このsetHTMLメソッドはサニタイザーインスタンスを受け入れ、新しいノードをDOMに挿入する前に、潜在的に有害なHTMLコンテンツをサニタイズします。

サニタイザーAPIの実験

Sanitizer APIの初期の実装は、GoogleChrome/Chromium≥93およびFirefox≥83のWebブラウザーで使用できます。これらの初期の実装は通常、どちらのWebブラウザーでもデフォルトで有効になっていないため、最初にブラウザー構成を変更して有効にする必要があります。

Chrome / Chromiumを使用している場合は、 URL#sanitizer-apiに移動して、次のように切り替えを有効にできます。chrome://flags

Mozilla Firefoxを使用している場合はabout:config、次のように、を介してこの機能を有効にできます。

このチュートリアルでは、Mozilla Firefox 96を使用して、今後のSanitizerAPIの例を試してみます。

実用的な例でサニタイザーAPIを試してみましょう。これらの例を示すためにJsFiddleオンラインエディターを使用しますが、HTMLファイルを作成することで、ローカルの開発環境でテストすることもできます。

安全でないHTML文字列をサニタイズし、DOMに挿入する

基本から始めましょう。Sanitizer APIを使用して、安全でないHTML文字列からより安全なDOMノードをレンダリングするにはどうすればよいですか?次のサンプルコードを見てください。

<div id="container"></div>
<script>
  // unsafe HTML string
  const unsafeHTML = `<p onclick="alert('Hello')">Hello</p>`;
  // Find the container node
  const container = document.getElementById('container');
  // Create a sanitizer object with the default config
  const sanitizer = new Sanitizer();
  // Inject new DOM nodes in a safer way
  container.setHTML(unsafeHTML, sanitizer);
</script>

ここでは、プロパティsetHTMLの代わりにセッターを使用しました。innerHTML上記のコードを実行した後にDOMを調べると、子要素をノードにレンダリングする前に、setHTMLメソッドが自動的に除外されていることがわかります。onclickcontainer

innerHTML次のコードを使用して、プロパティの不安定さを確認できます。

<div id="container"></div>
<script>
  // unsafe HTML string
  const unsafeHTML = `<p onclick="alert('Hello')">Hello</p>`;
  // Find the container node
  const container = document.getElementById('container');

  // Inject new DOM nodes
  container.innerHTML = unsafeHTML;
</script>

上記のコードは、以下に示すように、安全でないイベントハンドラーを使用して新しいDOMノードを挿入します。

プロパティのセキュリティ問題のデモンストレーションinnerHTML

innerHTMLサニタイズされたDOM要素のプロパティを読み取ることでサニタイズされた生のHTML文字列を取得できますが、サニタイザーAPIを安全に挿入するというサニタイザーAPIの背後にある主な目標をやや破ります。つまり、サニタイザーAPIを別のサニタイズライブラリとして使用しないでください。

怠惰な消毒sanitizeFor

以前は、このsetHTMLメソッドを使用して、サニタイズプロセスで安全でないHTML文字列をすぐにレンダリングしましたが、シナリオによっては、サニタイズプロセスの後で新しい要素をレンダリングする必要があります。

たとえば、Web開発者は、レンダリングプロセスの後に、インターネットからWYSIWYGエディタに安全でないHTML文字列をレンダリングする必要があることがよくあります。最適化されたエラーのないソリューションとして、最初にコンテンツをフェッチし、サニタイズを適用してから、エディターコンポーネントが完全にレンダリングされたときにサニタイズされたノードをレンダリングできます。

このメソッドを使用して、結果をサニタイズして特定のDOMノードとして一時的に保存できますsanitizeFor。次の例を見てください。

<div id="container">Loading...</div>
<script>
  // unsafe HTML string
  const unsafeHTML = `<p onclick="alert('Hello')">Hello</p>`;
  // Create a sanitizer object with the default config
  const sanitizer = new Sanitizer();
  // Hold sanitized node
  const sanitizedDiv = sanitizer.sanitizeFor('div', unsafeHTML);
  // Inject nodes after sometime
  setTimeout(() => {
    // Find the container node
    const container = document.getElementById('container');
    // Inject the sanitized DOM node
    container.replaceChildren(sanitizedDiv);  
  }, 1000);
</script>

上記のコードは、安全でないHTML文字列をサニタイズし、サニタイズされたDOMノードを定数に保存します。後で、メソッドを使用して、サニタイズされたDOMノードを関連するコンテナノードに挿入しますreplaceChildren。ネットワークとレンダリングの遅延をシミュレートするために、意図的に1秒の遅延を使用したことに注意してください。

関数の使用方法のデモンストレーションsanitizeFor

iframeのサニタイズ

iframeは、ウィジェットやサードパーティのWebページをWebアプリケーションに追加するのに役立ちますが、他のソース(多くの場合サードパーティのソース)からWebコンテンツをロードするため、通常はセキュリティ上の問題があります。したがって、iframeを介して読み込まれるWebコンテンツをサニタイズするのが間違いなく最も安全です。

以前は、サニタイズAPIメソッドの入力として文字列を使用していましたが、今度は、既存のDOMノードをサニタイズする必要があります。これを行うには、HTMLドキュメントフラグメントまたはドキュメントを受け入れる関数が必要です。

方法を覚えていsanitizeますか?次の例を見てください。

<iframe id="webpage"></iframe> <!-- Use a URL with cross-origin policy -->
<br/>
<button onclick="sanitize()">Sanitize</button>

<script>
function sanitize() {
  // Create a sanitizer object with the default config
  const sanitizer = new Sanitizer();
  // Find the iframe node
  const iframe = document.getElementById('webpage');
  // Sanitize the iframe's document node
  const sanitizedFrameNodes = sanitizer.sanitize(iframe.contentWindow.document);
  iframe.replaceChildren(sanitizeFrameNodes);
}
</script>

サニタイザー構成のカスタマイズ

構成オブジェクトを送信せずに新しいSanitizerクラスインスタンスを作成すると、APIはデフォルトの構成を使用して既知のXSSの脆弱性を軽減します。ただし、構成オブジェクトを送信することにより、サニタイズロジックをカスタマイズできます。

div動的要素に対して基本的なHTMLタグとインラインスタイルを許可する必要があると想定します。以下に示すように、カスタム構成を使用して、この要件に対応するサニタイザーを実装できます。

<div id="container"></div>
<script>
  // unsafe HTML string
  const unsafeHTML = `<div onclick="alert('Hello')">
   <p><b>Hello Sanitizer API</b></p>
    <p><em onmovemove="window.location.reload()">Test</em></p>
    <img src="image.png" alt="Test"/>
  </div>`;
  // Find the container node
  const container = document.getElementById('container');
  // Create a sanitizer object with a custom config
  const sanitizer = new Sanitizer(
    {
      'allowElements': [
        'div',
        'span',
        'p',
        'em',
        'b'
      ],
      'allowAttributes': {
        'style': ['*']
      }
    });
  // Inject new DOM nodes in a safer way
  const sanitizedDiv = sanitizer.sanitizeFor('div', unsafeHTML);
  container.replaceChildren(sanitizedDiv);
</script>

関数を使用しても同じ出力を達成できることに注意してください。ただし、Firefoxの実験関数にはサニタイズ後もタグが含まれているため、代わりsetHTMLに使用しました。replaceChildrensetHTMLimg

カスタムサニタイザー構成を使用する場合は注意してください。onclick構成をカスタマイズするときに、任意の要素と属性を許可するように完全に制御できます。たとえば、次のサニタイザー構成では、イベントハンドラーが許可されるため、WebアプリケーションがXSSになりやすくなります。

{
  'allowElements': ['div', 'p', 'em'],
  'allowAttributes': {
    'onclick': ['*']
  }
}

サニタイザーAPIの設定ミスに注意してください!

ブラウザのサポートとAPIステータス

ブラウザ開発者とセキュリティエンジニアは通常、一般的な承認を得るために新しいブラウザAPI提案をW3C組織に提出します。インキュベーション期間と承認の後、W3Cは特定の仕様を公式のWeb標準に追加します。

何人かの寄稿者が2016年にGitHubリポジトリでSanitizationAPIプロポーザルの作成を開始しました。2021年後半、API提案は公式のWebインキュベーターでドラフト段階に達しました。現在、Web開発者コミュニティは、さまざまなアイデアを提案することで仕様を改善し、公式のWeb標準にするよう努めています。

さらに、Google Chrome/Chromium≥93およびFirefox≥83は、それらを今すぐテストすることに関心のあるWeb開発者向けにSanitizerAPIの初期の実装を提供します。これらの初期の実装は安定しておらず、将来的に変更される可能性があります。完全なブラウザサポートの詳細は、CanIUseで確認できます。

ただし、このブラウザ機能は安全なコンテキストで機能します。つまり、このブラウザ機能はHTTPS接続でのみ使用できます。127.0.0.1ただし、標準のセキュアコンテキストポリシーはローカルホスト(または)をセキュアコンテキストとして識別するため、ローカル開発環境でSanitizerAPIを使用することもできます。

結論

このチュートリアルでは、いくつかの例を使用して実験的なSanitizer APIの使用方法を学び、ブラウザーの実験的な機能リストからそれを有効にすることから始めました。Google Chrome /ChromiumとMozillaFirefoxは、このAPI仕様の初期の実装を提供していますが、それでもW3Cインキュベータープログラムに含まれています。つまり、プロポーザルの編集者は、コミュニティの提案と既知のセキュリティの脆弱性に基づいてAPI仕様を変更する可能性があります。Sanitizer APIの構造を改善する提案がある場合は、GitHubのSanitizerAPIインキュベーターリポジトリに問題を送信できます。

Sanitizer APIは、フロントエンド開発者とフレームワーク開発者の両方を支援することを約束します。たとえば、React開発者は、安全でないHTML文字列をDOMにレンダリングするために、 sanitize-htmlライブラリとReactの小道具を使用する傾向があります。dangerouslySetInnerHTML

ただし、実験的なSanitizer APIがブラウザーの標準になると、Reactは、setHTMLバンドルサイズに影響を与えることなく、任意のHTML文字列をサニタイズおよび挿入するための開発者向けのメソッド(など)を提供できるようになります。

AngularなどのカスタムHTMLサニタイザー実装を使用するフレームワークは、ネイティブのSanitizationAPIを使用してフレームワークバンドルサイズを削減できます。ただし、前述のように、Sanitizer APIはまだ実験段階であるため、安定してW3Cで承認されるまで、本番システムで使用しないでください。

オンラインのHTMLSanitizerAPIプレイグラウンドを使用して、SanitizerAPIをさらに試すことができます。

このストーリーは、もともとhttps://blog.logrocket.com/what-you-need-know-inbuilt-browser-html-sanitization/で公開されました。

#browser #html 

What is GEEK

Buddha Community

組み込みのブラウザHTMLサニタイズについて知っておくべきこと
藤本  結衣

藤本 結衣

1654491660

組み込みのブラウザHTMLサニタイズについて知っておくべきこと

アプリケーションのセキュリティは、すべてのWebアプリケーションにとって重要な要素です。Web開発者は、脆弱性防止技術の実装など、さまざまな戦略を使用してWebアプリケーションのセキュリティ層を改善します。

通常、生のHTMLの処理を開始し、信頼できないコンテンツでDOMを操作すると、Webアプリケーションのセキュリティリスクが高まります。サードパーティのソースから直接HTMLをレンダリングしていて、そのソースがインターネットベースの脅威の影響を受ける場合、攻撃者はユーザーの同意なしにアプリケーションユーザーのコンピューターでJavaScriptコードを実行する可能性があります。これらのセキュリティ攻撃は、XSS(クロスサイトスクリプティング)攻撃として知られています。

HTMLサニタイズは、WebアプリケーションのXSS脆弱性を防ぐためにOWASPが推奨する戦略です。HTMLサニタイズは、信頼できない生のHTML文字列から安全でない(そして潜在的に悪意のある)コンテンツをユーザーに提示する前に削除するセキュリティメカニズムを提供します。

実験的な組み込みのブラウザSanitizationAPIは、信頼できないHTML文字列を安全な方法でWebアプリケーションのDOMに挿入するのに役立ちます。

HTMLサニタイズとは何ですか?

HTMLサニタイズとは、一般に、潜在的に悪意のあるJavaScriptコンテンツを生のHTML文字列から削除することを指します。2つの異なるHTMLサニタイズ実装があります。

  • クライアント側のサニタイズ:DOMレベルからの安全でないコンテンツを防止します
  • サーバー側のサニタイズ:悪意のあるHTMLコンテンツがデータベースに保存されるのを防ぎます

XSSの脆弱性を防ぐために、実際には両方のサニタイズレイヤーを使用する必要があります。データベースが悪意のあるXSSペイロードの影響を受ける場合、クライアント側のサニタイズレイヤーはすべてのアプリケーションユーザーを保護しますが、攻撃者が悪意のあるHTMLをRESTful APIから直接送信する場合、サーバー側のサニタイズはシステムを保護します。

Web開発者は、クライアント側/DOMレベルのサニタイズに次のライブラリを使用する傾向があります。

  • DOMPurity:JavaScript用のHTMLサニタイザーライブラリ
    • jsdomパッケージを介してサーバー側のNode.jsでも機能します
  • js-xss:ブラウザー、サーバー側のNode.jsで、コマンドラインツールとして機能するHTMLサニタイザーライブラリ
  • sanitize-html:Node.jsおよびブラウザー用のhtmlparser2ベースのサニタイザーライブラリ。特にReact用のラッパーライブラリがあるため、React開発者の間で非常に人気があります。

これらのライブラリは通常、ブラウザに組み込まれているDOMイテレータ、またはを使用する前に安全でないHTMLコンテンツを除外するカスタムHTMLパーサーのいずれかを使用して、安全でないHTMLを解析しますinnerHTML

ブラウザネイティブのサニタイズAPIが必要なのはなぜですか?

HTMLサニタイズAPIは、安全でないHTML文字列またはドキュメントをWebページに安全に追加するのに役立つブラウザ機能です。これは、既存のDOM要素をサニタイズし、生のHTML文字列から新しいサニタイズされたDOM要素を取得するためのメソッドを提供します。

上記のソリューションは、XSS攻撃を防ぐための非常に優れたセキュリティソリューションを提供しますが、それでもいくつかの問題があります。これらのライブラリは、ブラウザの標準が変更されたときに、サニタイズ仕様を最新の状態に保つ必要があります。たとえば、標準のHTML仕様で安全でない可能性のあるHTML属性が導入された場合、これらのライブラリのサニタイズ戦略は不安定になります。

 

ライブラリベースのサニタイズも遅くなる可能性があります。これは、安全なHTMLをWebページに挿入するときに、解析が2回(最初はライブラリのサニゼーションプロセス中に、もう1つはブラウザのDOM解析プロセス中に)行われるためです。

主な目標

HTML Sanitization APIの目標は、次の機能を介してDOMレベルのXSS攻撃を軽減することです。

  • 開発者向けに、完全な機能を備えた、完全で安定したネイティブサニタイズインターフェイスを提供します
  • 最新の標準HTML仕様をマッピングすることにより、最新のサニタイズ定義を維持します
  • 前述のサニタイズライブラリとは異なり、サニタイズされた生のHTML文字列を提供するのではなくDOMを保護する

ネイティブサニタイズの大きな魅力は、サニタイズルールに基づいてDOMを直接解析および操作するsetHTML関数を提供することです。

HTMLサニタイザーAPI仕様を理解する

サニタイザーAPIの背景、機能、現在の開発状況がわかったところで、JavaScript環境に公開されるAPI仕様を見てみましょう。

SanitizerSanitizer APIには、クラスとElement.setHTMLメソッドの2つの主要な開発者インターフェースが付属しています。

Sanitizerクラスと構成

このクラスは、サニタイズ要件に対応Sanitizerする新しいHTMLオブジェクトを作成するのに役立ちます。sanitizer次の構文が付属しています。

new Sanitizer()
new Sanitizer(config)

パラメーター化されていないコンストラクターを使用して、次の構文とデフォルト構成で新しいサニタイザーオブジェクトを作成できます。デフォルトの構成では、Sanitizer既知のXSSの脆弱性を軽減するために、セーフリストベースの手法でオブジェクトが作成されます。

const sanitizer = new Sanitizer();

ただし、Sanitizer以下に示すように、構成オブジェクトを渡すことでオブジェクトをカスタマイズできます。

const sanitizer = new Sanitizer(config);

configurationオブジェクトには次の定義があります。APIプロポーザルはまだWebインキュベーターにあるため、この構成定義は将来変更される可能性があることに注意してください。

{
  allowElements: <string Array>,
  blockElements: <string Array>,
  dropElements: <string Array>,
  allowAttributes: <Object>,
  dropAttributes: <Object>,
  allowCustomElements: <Boolean>,
  allowComments: <Boolean>
}
  • allowElements:消毒剤に含める必要のある要素のリスト
  • blockElements:サニタイザーが子要素を保持することによって除外する必要がある要素のリスト
  • dropElementsblockElementsプロパティなどの要素を除外しますが、除外されたノードに属する子要素ツリー全体も削除します
  • allowAttributes:キー配列オブジェクトとして許可された属性
    • たとえば、すべての要素'class': ['div']の属性を許可します—アスタリスク文字()を使用して、任意のHTML要素の特定の属性を許可できますclassdiv*
  • dropAttributesallowAttributes:プロパティの反対のバージョン
  • allowCustomElements:カスタム要素を許可または禁止するブール値(デフォルトはfalse
  • allowComments:コメントを許可または禁止するブール値(デフォルトはfalse

たとえば、Sanitizer以下に示すように、カスタムオブジェクトを開始して、基本的なHTMLタグとインラインスタイルのみを許可できます。

{
  'allowElements': [
    'div',
    'span',
    'p',
    'em',
    'b'
  ],
  'allowAttributes': {
    'style': ['*']
  }
}

サニタイザーAPIメソッド:sanitizesanitizeFor,およびsetHTML

このSanitizerクラスはHTMLオブジェクトを開始するのに役立ちSanitizerますが、Webアプリケーションでサニタイザーインスタンスを使用するには、他のいくつかのメソッドを使用する必要があります。次のAPI仕様を学習した後、チュートリアルセクションでサニタイザーAPIの使用方法を説明します。

Sanitizer.sanitize方法

サニタイズ(入力)

このメソッドを使用して、sanitize既存のDOMノードにサニタイザールールを適用できます。Documentこの関数はorDocumentFragmentオブジェクトを受け入れ、サニタイズさDocumentFragmentれたものを出力として返します。

Sanitizer.sanitizeFor方法

sanitizeFor(element, input)

このメソッドを使用して、安全でないHTML文字列を送信することにより、サニタイズされた要素ノードを取得できます。つまり、サニタイズルールに従って文字列elementを解析した後、タイプDOMノードを返します。input

Element.setHTML方法

setHTML(input, sanitizer)

このメソッドは、Element.innerHTMLプロパティのより安全でより設定されたバージョンです。このinnerHTMLプロパティは任意のHTML文字列を許可し、XSSペイロードの傾向があります。したがって、このsetHTMLメソッドはサニタイザーインスタンスを受け入れ、新しいノードをDOMに挿入する前に、潜在的に有害なHTMLコンテンツをサニタイズします。

サニタイザーAPIの実験

Sanitizer APIの初期の実装は、GoogleChrome/Chromium≥93およびFirefox≥83のWebブラウザーで使用できます。これらの初期の実装は通常、どちらのWebブラウザーでもデフォルトで有効になっていないため、最初にブラウザー構成を変更して有効にする必要があります。

Chrome / Chromiumを使用している場合は、 URL#sanitizer-apiに移動して、次のように切り替えを有効にできます。chrome://flags

Mozilla Firefoxを使用している場合はabout:config、次のように、を介してこの機能を有効にできます。

このチュートリアルでは、Mozilla Firefox 96を使用して、今後のSanitizerAPIの例を試してみます。

実用的な例でサニタイザーAPIを試してみましょう。これらの例を示すためにJsFiddleオンラインエディターを使用しますが、HTMLファイルを作成することで、ローカルの開発環境でテストすることもできます。

安全でないHTML文字列をサニタイズし、DOMに挿入する

基本から始めましょう。Sanitizer APIを使用して、安全でないHTML文字列からより安全なDOMノードをレンダリングするにはどうすればよいですか?次のサンプルコードを見てください。

<div id="container"></div>
<script>
  // unsafe HTML string
  const unsafeHTML = `<p onclick="alert('Hello')">Hello</p>`;
  // Find the container node
  const container = document.getElementById('container');
  // Create a sanitizer object with the default config
  const sanitizer = new Sanitizer();
  // Inject new DOM nodes in a safer way
  container.setHTML(unsafeHTML, sanitizer);
</script>

ここでは、プロパティsetHTMLの代わりにセッターを使用しました。innerHTML上記のコードを実行した後にDOMを調べると、子要素をノードにレンダリングする前に、setHTMLメソッドが自動的に除外されていることがわかります。onclickcontainer

innerHTML次のコードを使用して、プロパティの不安定さを確認できます。

<div id="container"></div>
<script>
  // unsafe HTML string
  const unsafeHTML = `<p onclick="alert('Hello')">Hello</p>`;
  // Find the container node
  const container = document.getElementById('container');

  // Inject new DOM nodes
  container.innerHTML = unsafeHTML;
</script>

上記のコードは、以下に示すように、安全でないイベントハンドラーを使用して新しいDOMノードを挿入します。

プロパティのセキュリティ問題のデモンストレーションinnerHTML

innerHTMLサニタイズされたDOM要素のプロパティを読み取ることでサニタイズされた生のHTML文字列を取得できますが、サニタイザーAPIを安全に挿入するというサニタイザーAPIの背後にある主な目標をやや破ります。つまり、サニタイザーAPIを別のサニタイズライブラリとして使用しないでください。

怠惰な消毒sanitizeFor

以前は、このsetHTMLメソッドを使用して、サニタイズプロセスで安全でないHTML文字列をすぐにレンダリングしましたが、シナリオによっては、サニタイズプロセスの後で新しい要素をレンダリングする必要があります。

たとえば、Web開発者は、レンダリングプロセスの後に、インターネットからWYSIWYGエディタに安全でないHTML文字列をレンダリングする必要があることがよくあります。最適化されたエラーのないソリューションとして、最初にコンテンツをフェッチし、サニタイズを適用してから、エディターコンポーネントが完全にレンダリングされたときにサニタイズされたノードをレンダリングできます。

このメソッドを使用して、結果をサニタイズして特定のDOMノードとして一時的に保存できますsanitizeFor。次の例を見てください。

<div id="container">Loading...</div>
<script>
  // unsafe HTML string
  const unsafeHTML = `<p onclick="alert('Hello')">Hello</p>`;
  // Create a sanitizer object with the default config
  const sanitizer = new Sanitizer();
  // Hold sanitized node
  const sanitizedDiv = sanitizer.sanitizeFor('div', unsafeHTML);
  // Inject nodes after sometime
  setTimeout(() => {
    // Find the container node
    const container = document.getElementById('container');
    // Inject the sanitized DOM node
    container.replaceChildren(sanitizedDiv);  
  }, 1000);
</script>

上記のコードは、安全でないHTML文字列をサニタイズし、サニタイズされたDOMノードを定数に保存します。後で、メソッドを使用して、サニタイズされたDOMノードを関連するコンテナノードに挿入しますreplaceChildren。ネットワークとレンダリングの遅延をシミュレートするために、意図的に1秒の遅延を使用したことに注意してください。

関数の使用方法のデモンストレーションsanitizeFor

iframeのサニタイズ

iframeは、ウィジェットやサードパーティのWebページをWebアプリケーションに追加するのに役立ちますが、他のソース(多くの場合サードパーティのソース)からWebコンテンツをロードするため、通常はセキュリティ上の問題があります。したがって、iframeを介して読み込まれるWebコンテンツをサニタイズするのが間違いなく最も安全です。

以前は、サニタイズAPIメソッドの入力として文字列を使用していましたが、今度は、既存のDOMノードをサニタイズする必要があります。これを行うには、HTMLドキュメントフラグメントまたはドキュメントを受け入れる関数が必要です。

方法を覚えていsanitizeますか?次の例を見てください。

<iframe id="webpage"></iframe> <!-- Use a URL with cross-origin policy -->
<br/>
<button onclick="sanitize()">Sanitize</button>

<script>
function sanitize() {
  // Create a sanitizer object with the default config
  const sanitizer = new Sanitizer();
  // Find the iframe node
  const iframe = document.getElementById('webpage');
  // Sanitize the iframe's document node
  const sanitizedFrameNodes = sanitizer.sanitize(iframe.contentWindow.document);
  iframe.replaceChildren(sanitizeFrameNodes);
}
</script>

サニタイザー構成のカスタマイズ

構成オブジェクトを送信せずに新しいSanitizerクラスインスタンスを作成すると、APIはデフォルトの構成を使用して既知のXSSの脆弱性を軽減します。ただし、構成オブジェクトを送信することにより、サニタイズロジックをカスタマイズできます。

div動的要素に対して基本的なHTMLタグとインラインスタイルを許可する必要があると想定します。以下に示すように、カスタム構成を使用して、この要件に対応するサニタイザーを実装できます。

<div id="container"></div>
<script>
  // unsafe HTML string
  const unsafeHTML = `<div onclick="alert('Hello')">
   <p><b>Hello Sanitizer API</b></p>
    <p><em onmovemove="window.location.reload()">Test</em></p>
    <img src="image.png" alt="Test"/>
  </div>`;
  // Find the container node
  const container = document.getElementById('container');
  // Create a sanitizer object with a custom config
  const sanitizer = new Sanitizer(
    {
      'allowElements': [
        'div',
        'span',
        'p',
        'em',
        'b'
      ],
      'allowAttributes': {
        'style': ['*']
      }
    });
  // Inject new DOM nodes in a safer way
  const sanitizedDiv = sanitizer.sanitizeFor('div', unsafeHTML);
  container.replaceChildren(sanitizedDiv);
</script>

関数を使用しても同じ出力を達成できることに注意してください。ただし、Firefoxの実験関数にはサニタイズ後もタグが含まれているため、代わりsetHTMLに使用しました。replaceChildrensetHTMLimg

カスタムサニタイザー構成を使用する場合は注意してください。onclick構成をカスタマイズするときに、任意の要素と属性を許可するように完全に制御できます。たとえば、次のサニタイザー構成では、イベントハンドラーが許可されるため、WebアプリケーションがXSSになりやすくなります。

{
  'allowElements': ['div', 'p', 'em'],
  'allowAttributes': {
    'onclick': ['*']
  }
}

サニタイザーAPIの設定ミスに注意してください!

ブラウザのサポートとAPIステータス

ブラウザ開発者とセキュリティエンジニアは通常、一般的な承認を得るために新しいブラウザAPI提案をW3C組織に提出します。インキュベーション期間と承認の後、W3Cは特定の仕様を公式のWeb標準に追加します。

何人かの寄稿者が2016年にGitHubリポジトリでSanitizationAPIプロポーザルの作成を開始しました。2021年後半、API提案は公式のWebインキュベーターでドラフト段階に達しました。現在、Web開発者コミュニティは、さまざまなアイデアを提案することで仕様を改善し、公式のWeb標準にするよう努めています。

さらに、Google Chrome/Chromium≥93およびFirefox≥83は、それらを今すぐテストすることに関心のあるWeb開発者向けにSanitizerAPIの初期の実装を提供します。これらの初期の実装は安定しておらず、将来的に変更される可能性があります。完全なブラウザサポートの詳細は、CanIUseで確認できます。

ただし、このブラウザ機能は安全なコンテキストで機能します。つまり、このブラウザ機能はHTTPS接続でのみ使用できます。127.0.0.1ただし、標準のセキュアコンテキストポリシーはローカルホスト(または)をセキュアコンテキストとして識別するため、ローカル開発環境でSanitizerAPIを使用することもできます。

結論

このチュートリアルでは、いくつかの例を使用して実験的なSanitizer APIの使用方法を学び、ブラウザーの実験的な機能リストからそれを有効にすることから始めました。Google Chrome /ChromiumとMozillaFirefoxは、このAPI仕様の初期の実装を提供していますが、それでもW3Cインキュベータープログラムに含まれています。つまり、プロポーザルの編集者は、コミュニティの提案と既知のセキュリティの脆弱性に基づいてAPI仕様を変更する可能性があります。Sanitizer APIの構造を改善する提案がある場合は、GitHubのSanitizerAPIインキュベーターリポジトリに問題を送信できます。

Sanitizer APIは、フロントエンド開発者とフレームワーク開発者の両方を支援することを約束します。たとえば、React開発者は、安全でないHTML文字列をDOMにレンダリングするために、 sanitize-htmlライブラリとReactの小道具を使用する傾向があります。dangerouslySetInnerHTML

ただし、実験的なSanitizer APIがブラウザーの標準になると、Reactは、setHTMLバンドルサイズに影響を与えることなく、任意のHTML文字列をサニタイズおよび挿入するための開発者向けのメソッド(など)を提供できるようになります。

AngularなどのカスタムHTMLサニタイザー実装を使用するフレームワークは、ネイティブのSanitizationAPIを使用してフレームワークバンドルサイズを削減できます。ただし、前述のように、Sanitizer APIはまだ実験段階であるため、安定してW3Cで承認されるまで、本番システムで使用しないでください。

オンラインのHTMLSanitizerAPIプレイグラウンドを使用して、SanitizerAPIをさらに試すことができます。

このストーリーは、もともとhttps://blog.logrocket.com/what-you-need-know-inbuilt-browser-html-sanitization/で公開されました。

#browser #html