Sanitizer APIのその後
UI開発者 加藤2022年にSanitizer APIの使い方という記事を公開しました。
一時はGoogle Chromeに実装されたものの、その後APIの仕様が大きく変更されることになり、Sanitizer APIの実装は取り下げられることになりました。
explainerに記載されている「The Problem」や「Goals」に変更はありませんが、APIについては変更されています。冒頭に記載した2022年の記事も当時のAPI仕様をもとに執筆したものであり、今では古い情報となっていますのでご注意いただければと思います。
本記事では、その後のSanitizer APIの状況を書きたいと思います。しかし、今回記載する内容もWICGで検討している段階であり、まだ確定していないという点はご留意ください。また、この記事は、2024年6月時点の情報をもとに執筆しています。
仕様の変更点
冒頭に記載した記事では、Sanitizer APIの使い方として以下の2通りを紹介しました。
Element.setHTML
メソッドの引数に指定する- Sanitizer APIを直接使う
このうち後者のSanitizer APIを直接使う方法は、仕様から削除されました。
メソッドの引数に指定する使い方では、Element.setHTML
だけでなくElement.setHTMLUnsafe
、Document.parseHTML
、Document.parseHTMLUnsafe
と組み合わせて使うことが想定されています。
この記事では、XSSのリスクがより少ないことを「安全」と表現し、以降はsetHTML
とparseHTML
を「安全なバージョンのメソッド」、setHTMLUnsafe
とparseHTMLUnsafe
を「安全でないバージョンのメソッド」と呼びます。
ちなみに、それぞれの安全ではないバージョンのメソッドはすでにHTML Standardに追加されており、Web Platform StatusでもNewly availableとしてマークされています。
また、setHTML
とsetHTMLUnsafe
はElement
だけでなくShadowRoot
でも同様に機能するよう想定されています。
Sanitizer APIをどう使うか
Sanitizer APIが今の仕様で確定となった場合、大きく以下の2つがブラウザに実装されるはずです。
- 安全ではないバージョンのメソッドの第二引数にサニタイジングの設定を指定できるようになる
- デフォルトで安全なバージョンのメソッドが追加される
それぞれを簡単に解説します。
安全ではないバージョンのメソッドの変更
具体的には、setHTMLUnsafe
とparseHTMLUnsafe
の第二引数に以下の設定をオブジェクトで指定できるようになります。
elements
: サニタイジング時に削除しない要素を指定するremoveElements
: サニタイジング時に削除する要素を指定するreplaceWithChildrenElements
: サニタイジング時に削除するが、テキストフラグメントを含む子要素は残す要素を指定するattributes
: サニタイジング時に削除しない属性を指定するremoveAttributes
: サニタイジング時に削除する属性を指定するcomments
: HTMLコメントを残すかどうかを指定するdataAttributes
:data-
から始まるカスタムデータ属性を残すかどうかを指定する
例えば、挿入するHTMLからscript
要素を削除したい場合は以下のようなコードになります。
const sanitizingConfig = new Sanitizer({
'removeElements': [{name: 'script'}],
});
const html = '<script>alert(1);</script>';
const element = document.createElement('div');
element.setHTMLUnsafe(html, {sanitizer: sanitizingConfig});
console.log(element.outerHTML); // <div></div>
以下のように特定の要素の、特定の属性だけを対象とするような設定も想定されています。
const sanitizingConfig = new Sanitizer({
elements: [
{name: 'img', attributes: ['src']}, // img要素のsrc属性は削除しない
{name: 'input', removeAttributes: ['src']} // input要素のsrc属性は削除する
],
});
矛盾する設定を指定すると例外がスローされます。
const sanitizingConfig = new Sanitizer({
elements: ['div'],
removeElements: ['div'],
});
element.setHTML('<script></script>', {sanitizer: sanitizingConfig});
安全なバージョンのメソッド
安全なバージョンのメソッドでは、script
要素やonclick
属性など、XSSのリスクがあるコンテンツをデフォルトで削除します。
const html = '<script>alert(1);</script>';
const element = document.createElement('div');
element.setHTML(html); // <div></div>
安全なバージョンのメソッドも、安全でないバージョンのメソッドと同様にサニタイジングの設定を指定できますが、指定された設定のうち安全でない設定は無視されるため、<script>
要素を許可するような設定をしても無視されます。
const sanitizingConfig = new Sanitizer({
elements: ['script'], // script要素を許可する設定
});
const html = '<script>alert(1);</script>';
const element = document.createElement('div');
element.setHTML(html, sanitizingConfig); // <div></div>
おわりに
以上、Sanitizer APIの現状を簡単にまとめてみました。繰り返しになりますが、仕様はまだ検討段階であり今後変更される可能性もあります。GitHubのIssueを見ている限りだと安全なバージョンのメソッドで許可する要素や属性の議論などが続いており、WHATWGの仕様として導入されるのはもう少し先になりそうな印象です。
また進展があれば記事にしたいと思います。