DOMPurify は、HTML、MathML、SVG 用の DOM 専用、超高速、超耐性の XSS サニタイザーです。
使い方も使い始めるのもとても簡単です。 DOMPurify は 2014 年 2 月に開始され、その間にバージョンv3.2.1に達しました。
DOMPurify は JavaScript で書かれており、すべての最新のブラウザ (Safari (10 以降)、Opera (15 以降)、Edge、Firefox、Chrome、および Blink、Gecko、WebKit を使用するほぼすべてのブラウザ) で動作します。 MSIE や他のレガシー ブラウザでは壊れません。それは単に何もしません。
DOMPurify v2.5.7 が MSIE をサポートする最新バージョンであることに注意してください。 MSIE と互換性のある重要なセキュリティ更新プログラムについては、2.x ブランチを使用してください。
当社の自動テストは現在 24 種類のブラウザをカバーしていますが、さらに増える予定です。 jsdom 上で DOMPurify を実行する Node.js v16.x、v17.x、v18.x、および v19.x についても説明します。古いバージョンの Node も同様に動作することが知られていますが、保証はありません。
DOMPurify は、Web 攻撃と XSS に豊富な経験を持つセキュリティ担当者によって作成されました。恐れることはありません。詳細については、セキュリティの目標と脅威モデルについてもお読みください。ぜひ読んでみてください。そうですね、本当に。
DOMPurify は HTML をサニタイズし、XSS 攻撃を防ぎます。汚い HTML でいっぱいの文字列を DOMPurify にフィードすると、(別途設定されていない限り) クリーンな HTML を含む文字列が返されます。 DOMPurify は危険な HTML を含むものをすべて削除し、XSS 攻撃やその他の厄介な行為を防ぎます。それもめちゃくちゃ速いです。ブラウザーが提供するテクノロジーを使用して、XSS フィルターに変換します。ブラウザが高速であればあるほど、DOMPurify も高速になります。
簡単です。ウェブサイトに DOMPurify を含めるだけです。
<script type="text/javascript" src="src/purify.js"></script>
<script type="text/javascript" src="dist/purify.min.js"></script>
その後、次のコードを実行して文字列をサニタイズできます。
const clean = DOMPurify.sanitize(dirty);
あるいは、Angular などで作業するのが好きな場合は、次のようにすることもできます。
import DOMPurify from 'dompurify';const clean = DOMPurify.sanitize('<b>こんにちは</b>');
結果の HTML は、 innerHTML
使用して DOM 要素に書き込むことも、 document.write()
使用して DOM に書き込むこともできます。それは完全にあなた次第です。デフォルトでは、HTML、SVG 、およびMathML が許可されていることに注意してください。非常に一般的な使用例である HTML のみが必要な場合は、それも簡単に設定できます。
const clean = DOMPurify.sanitize(dirty, { USE_PROFILES: { html: true } });
最初にHTML をサニタイズし、その後変更すると、サニタイズの効果が簡単に無効になる可能性があることに注意してください。サニタイズ後にサニタイズされたマークアップを別のライブラリにフィードする場合は、ライブラリが独自に HTML をいじらないようにしてください。
マークアップをサニタイズした後、プロパティDOMPurify.removed
を見て、どの要素と属性がスローされたかを確認することもできます。セキュリティ上重要な決定を行うためにこのプロパティを使用しないでください。これは、好奇心旺盛な人のためのほんの少しの助けです。
DOMPurify は技術的には、Node.js を使用してサーバー側でも動作します。私たちのサポートは、Node.js のリリース サイクルに従うよう努めています。
サーバー上で DOMPurify を実行するには、DOM が存在する必要がありますが、これはおそらく驚くべきことではありません。通常は、 jsdom が最適なツールであり、最新バージョンのjsdom を使用することを強くお勧めします。
なぜ?古いバージョンのjsdomには、DOMPurify がすべてを 100% 正しく実行したとしてもXSS を引き起こすバグがあることが知られているためです。たとえば、 jsdom v19.0.0には既知の攻撃ベクトルがあり、 jsdom v20.0.0では修正されています。そのため、 jsdom を最新の状態に保つことを強くお勧めします。
また、happy-dom のようなツールは存在しますが、現時点では安全とは考えられていないことにも注意してください。 DOMPurify とhappy-domを組み合わせることは現時点では推奨されておらず、XSS が発生する可能性があります。
それ以外は、サーバー上で DOMPurify を使用しても問題ありません。おそらく。これは実際には、 jsdomまたはサーバー側で使用する DOM に依存します。それを許容できる場合は、次のようにして機能させることができます。
npm インストール dompurify npm インストール jsdom
jsdom (最新バージョンを使用してください) の場合は、これでうまくいくはずです。
const createDOMPurify = require('dompurify');const { JSDOM } = require('jsdom');const window = new JSDOM('').window;const DOMPurify = createDOMPurify(window);const clean = DOMPurify.sanitize(' <b>こんにちは</b>');
インポートを使用したい場合は、次のようにすることもできます。
import { JSDOM } from 'jsdom';import DOMPurify from 'dompurify';const window = new JSDOM('').window;const purify = DOMPurify(window);const clean = purify.sanitize('<b>こんにちは< /b>');
特定の設定で動作させるのに問題がある場合は、人々が遭遇する可能性のある多くの問題を解決する素晴らしい isomorphic-dompurify プロジェクトを検討してください。
npm install isomorphic-dompurify
import DOMPurify from 'isomorphic-dompurify';const clean = DOMPurify.sanitize('<s>hello</s>');
もちろんデモもございます! DOMPurify で遊ぶ
まず、修正に取り組むことができるよう、すぐにメールでご連絡ください。 PGPキー
また、おそらくバグ報奨金の対象となるでしょう。 Fastmail の優れた人々はサービスに DOMPurify を使用しており、バグ報奨金の範囲に私たちのライブラリを追加しました。したがって、DOMPurify をバイパスまたは弱める方法を見つけた場合は、その Web サイトとバグ報奨金情報もご覧ください。
精製されたマークアップはどのようになりますか?まあ、デモでは厄介な要素が大量にあることが示されています。ただし、より小さな例もいくつか示してみましょう。
DOMPurify.sanitize('<img src=x onerror=alert(1)//>'); // <img src="x">DOMPurify.sanitize('<svg><g/onload=alert(2)//<p>') になります。 // <svg><g></g></svg>DOMPurify.sanitize('<p>abc<iframe//src=jAva	script:alert(3)>def</p>'); になります。 // <p>abc</p>DOMPurify.sanitize('<math><mi//xlink:href="data:x,<script>alert(4)</script>">'); になります。 // <math><mi></mi></math>DOMPurify.sanitize('<TABLE><tr><td>HELLO</tr></TABL>') になります。 // <table><tbody><tr><td>HELLO</td></tr></tbody></table>DOMPurify.sanitize('<UL><li><A HREF=//google) になります.com>クリック</UL>'); // <ul><li><a href="//google.com">クリック</a></li></ul>になります
DOMPurify は現在、HTML5、SVG、および MathML をサポートしています。 DOMPurify では、デフォルトで CSS、HTML カスタム データ属性が許可されます。 DOMPurify は Shadow DOM もサポートしており、DOM テンプレートを再帰的にサニタイズします。 DOMPurify を使用すると、既知の問題を発生させることなく、jQuery $()
およびelm.html()
API で使用できるように HTML をサニタイズすることもできます。
DOMPurify は何も行いません。与えられた文字列をそのまま返すだけです。 DOMPurify は、 isSupported
と呼ばれるプロパティを公開します。これにより、DOMPurify がそのジョブを実行できるかどうかがわかり、独自のバックアップ計画を立てることができます。
バージョン 1.0.9 では、信頼できるタイプ API のサポートが DOMPurify に追加されました。バージョン 2.0.0 では、これに関する DOMPurify の動作を制御するための設定フラグが追加されました。
Trusted Types API が利用可能でRETURN_TRUSTED_TYPE
がtrue
に設定されている環境でDOMPurify.sanitize
が使用される場合、文字列の代わりにTrustedHTML
値を返そうとします ( RETURN_DOM
およびRETURN_DOM_FRAGMENT
構成オプションの動作は変わりません)。
DOMPurify を使用してtrustedTypes
でポリシーを作成するには、 createHTML
TrustedHTML
ではなく通常の文字列を想定しているため、 RETURN_TRUSTED_TYPE: false
が必要であることに注意してください。以下の例はこれを示しています。
window.trustedTypes!.createPolicy('default', { createHTML: (to_escape) =>DOMPurify.sanitize(to_escape, { RETURN_TRUSTED_TYPE: false }),});
はい。含まれているデフォルトの構成値はすでにかなり優れていますが、もちろんそれらをオーバーライドすることもできます。 /demos
フォルダーをチェックして、DOMPurify をカスタマイズする方法に関する多数の例を確認してください。
// テンプレート システムに対して出力を安全にするために、{{ ... }}、${ ... } および <% ... %> を削除します// 注意してください、このモードは運用環境での使用には推奨されません。// 許可ユーザー制御の HTML でのテンプレート解析はまったくお勧めできません。// 本当に代替手段がない場合にのみ、このモードを使用してください。const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_TEMPLATES: true});// 方法を変更します。危険な HTML 文字を含むコメントは処理されます。// 非常に注意してください。この設定は、実際に HTML のみを処理し、// SVG や MathML などを処理しない場合にのみ「false」に設定する必要があります。 // それ以外の場合、「true」から「false」に変更すると、この方法または他の方法で XSS が発生します。const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_XML: false});
// <b> 要素のみを許可します。非常に厳密ですconst clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b']});// スタイル属性を持つ <b> と <q> のみを許可しますconst clean = DOMPurify.sanitize(ダーティ, {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style']});// すべて許可安全な HTML 要素ですが、SVG も MathML もありません// USE_PROFILES 設定は ALLOWED_TAGS 設定をオーバーライドすることに注意してください// したがって、これらを一緒に使用しないでくださいconst clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {html: true}});//すべての安全な SVG 要素と SVG フィルターを許可します。HTML または MathMLconst clean = は許可しません。 DOMPurify.sanitize(dirty, {USE_PROFILES: {svg: true, svgFilters: true}});// すべての安全な MathML 要素と SVG を許可しますが、SVG フィルターは許可しませんconst clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {mathMl: true) , svg: true}});// デフォルトの名前空間を HTML からsomething Differentconst clean = DOMPurify.sanitize(dirty, {NAMESPACE: 'http://www.w3.org/2000/svg'});// すべての安全な HTML をそのままにして、<style> 要素を block-listconst に追加しますclean = DOMPurify.sanitize(dirty, {FORBID_TAGS: ['style']});// すべての安全な HTML をそのままにして、スタイル属性を追加しますblock-listconst clean = DOMPurify.sanitize(dirty, {FORBID_ATTR: ['style']});// 許可されたタグの既存の配列を拡張し、<my-tag> をallow-listconst clean = DOMPurify.sanitize(dirty, {ADD_TAGS: ['my-tag']});// 許可された属性の既存の配列を拡張し、my-attr をallow-listconst clean = に追加します。 DOMPurify.sanitize(dirty, {ADD_ATTR: ['my-attr']});// ARIA 属性を禁止し、他の安全な HTML はそのままにします (デフォルトは true)const clean = DOMPurify.sanitize(dirty, {ALLOW_ARIA_ATTR: false} );// HTML5 データ属性を禁止し、他の安全な HTML はそのままにしておきます (デフォルトは true)const clean = DOMPurify.sanitize(ダーティ、{ALLOW_DATA_ATTR: false});
// DOMPurify を使用すると、カスタム要素のルールを定義できます。 CUSTOM_ELEMENT_HANDLING// リテラルを使用すると、許可する要素を正確に定義できます (デフォルトでは、何も許可されません)。//// 属性についても同様です。デフォルトでは、組み込みまたは設定されたallow.listが使用されます。//// RegExpリテラルを使用して、許可する内容または述語を指定できます。両方の例を以下に示します。// デフォルト値は非常に制限的です。偶発的な XSS バイパスを防ぐため。取り扱いには細心の注意を払ってください。const clean = DOMPurify.sanitize('<foo-bar baz="foobar"禁断="true"></foo-bar><div is="foo-baz"></div>', {CUSTOM_ELEMENT_HANDLING: {tagNameCheck: null, // カスタム要素は許可されませんattributeNameCheck: null, // デフォルト / 標準属性の許可リストが使用されますallowCustomizedBuiltInElements: false, // カスタマイズされた組み込みは許可されません},}); // <div is=""></div>const clean = DOMPurify.sanitize('<foo-bar baz="foobar"禁断="true"></foo-bar><div is="foo-baz "></div>',{CUSTOM_ELEMENT_HANDLING: {tagNameCheck: /^foo-/, // 「foo-」で始まるすべてのタグを許可しますattributeNameCheck: /baz/, // 「baz」を含むすべての属性を許可しますallowCustomizedBuiltInElements: true, // カスタマイズされた組み込みは許可されます},}); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>const clean = DOMPurify.sanitize('<foo-bar baz="foobar"禁断="true"></foo-bar><div is="foo-baz"></div>',{CUSTOM_ELEMENT_HANDLING: {tagNameCheck: (tagName) => tagName.match(/^foo-/), // 「foo-」で始まるすべてのタグを許可しますattributeNameCheck: (attr) => attr.match(/baz/), // 「baz」を含むすべてのタグを許可しますallowCustomizedBuiltInElements: true, // カスタマイズされた組み込みを許可します},}); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>
// データ URIsconst を使用できる既存の要素の配列を拡張します clean = DOMPurify.sanitize(dirty, {ADD_DATA_URI_TAGS: ['a', 'area']});// URI に対して安全な要素の既存の配列を拡張します。同様の値 (XSS リスクに注意してください)const clean = DOMPurify.sanitize(dirty, {ADD_URI_SAFE_ATTR: ['私の属性']});
// URL 属性で外部プロトコル ハンドラーを許可します (デフォルトは false、XSS のリスクに注意してください)// デフォルトでは、http、https、ftp、ftps、tel、mailto、callto、sms、cid、および xmpp のみが許可されます。const clean = DOMPurify.sanitize(dirty, {ALLOW_UNKNOWN_PROTOCOLS: true});// 正規表現を介して URL 属性で特定のプロトコル ハンドラーを許可します (デフォルト)は false です。注意してください。XSS のリスクがあります)// デフォルトでは、http、https、ftp、ftps、tel、mailto、callto、sms、cid、および xmpp のみが許可されます。// デフォルトの正規表現: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^az]|[a-z+.-]+(?:[^ a-z+.-:]|$))/i;const clean = DOMPurify.sanitize(dirty, {ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|xxx):|[^az]|[a-z+.-]+(?: [^a-z+.-:]|$))/i});
// HTML 文字列の代わりに DOM HTMLBodyElement を返します (デフォルトは false)const clean = DOMPurify.sanitize(dirty, {RETURN_DOM: true});// HTML 文字列の代わりに DOM DocumentFragment を返します (デフォルトは false)const clean = DOMPurify.sanitize(dirty, {RETURN_DOM_FRAGMENT: true});// を使用します。 RETURN_TRUSTED_TYPE フラグは、利用可能な場合に信頼できるタイプのサポートをオンにしますconst clean = DOMPurify.sanitize(dirty, {RETURN_TRUSTED_TYPE: true}); // 可能な場合は文字列の代わりに TrustedHTML オブジェクトを返します// 提供された Trusted Types ポリシーを使用しますconst clean = DOMPurify.sanitize(dirty, {// 提供されたポリシーは createHTML と createScriptURLTRUSTED_TYPES_POLICY を定義する必要があります:trustedTypes.createPolicy({createHTML(s) { return s},createScriptURL(s) { return s},}});
// <html> タグを含むドキュメント全体を返します (デフォルトは false)const clean = DOMPurify.sanitize(dirty, {WHOLE_DOCUMENT: true});// 出力時の DOM クローバリング保護を無効にします (デフォルトは true、慎重に扱ってください、マイナー XSSここにリスクがあります)const clean = DOMPurify.sanitize(dirty, {SANITIZE_DOM: false});// 厳格な DOM 破壊保護を適用します。名前空間分離 (デフォルトは false)// 有効にすると、文字列 `user-content-`const clean = をプレフィックスとして付けて、名前付きプロパティ (つまり、`id` 属性と `name` 属性)// JS 変数から名前空間を分離します。 DOMPurify.sanitize(dirty, {SANITIZE_NAMED_PROPS: true});// 要素が削除されたときに要素のコンテンツを保持します (デフォルトは true)const clean = DOMPurify.sanitize(dirty, {KEEP_CONTENT: false});// style、script、その他の要素を document.body に接着し、いくつかのエッジケースでのブラウザーの直感的でない動作を防止します (デフォルトは false) const clean = DOMPurify.sanitize(dirty , {FORCE_BODY: true});// 削除される <p> 要素の下にあるすべての <a> 要素を削除しますconst clean = DOMPurify.sanitize(dirty, {FORBID_CONTENTS: ['a'], FORBID_TAGS: ['p']});// サニタイズされたデータがデフォルトの HTML ではなく XML として扱われるようにパーサー タイプを変更しますconst clean = DOMPurify .sanitize(ダーティ, {PARSER_MEDIA_TYPE: 'application/xhtml+xml'});
// IN_PLACE モードを使用してノードを「その場で」サニタイズします。これは、DOMPurifyconst の使用方法に応じてはるかに高速です。 )');const clean = DOMPurify.sanitize(dirty, {IN_PLACE: true}); // 詳細については、https://github.com/cure53/DOMPurify/issues/288 を参照してください。
ここにはさらに多くの例があり、ニーズに合わせて DOMPurify を実行、カスタマイズ、構成する方法を示しています。
同じ設定を繰り返しDOMPurify.sanitize
に渡す代わりに、 DOMPurify.setConfig
メソッドを使用できます。構成は、次にDOMPurify.setConfig
を呼び出すまで、またはDOMPurify.clearConfig
呼び出してリセットするまで保持されます。アクティブな設定は 1 つだけであることに注意してください。つまり、一度設定されると、 DOMPurify.sanitize
に渡される追加の設定パラメータはすべて無視されます。
DOMPurify では、 DOMPurify.addHook
メソッドを使用して 1 つ以上の関数を次のフックのいずれかに接続することで、その機能を拡張できます。
beforeSanitizeElements
uponSanitizeElement
(「なし」 - すべての要素に対して呼び出されます)
afterSanitizeElements
beforeSanitizeAttributes
uponSanitizeAttribute
afterSanitizeAttributes
beforeSanitizeShadowDOM
uponSanitizeShadowNode
afterSanitizeShadowDOM
必要に応じて、現在処理されている DOM ノードを、検証済みのノードと属性データを含むリテラル、および DOMPurify 設定をコールバックに渡します。 MentalJS フックのデモをチェックして、API がどのようにうまく使用できるかを確認してください。
例:
DOMPurify.addHook( 'onSanitizeAttribute', function (currentNode, hackEvent, config) {// 現在のノードで何かを行います// 現在のノードのフックイベントを変更することもできます (つまり、hookEvent.forceKeepAttr = true に設定します)// 'uponSanitizeAttribute' 以外のフック タイプの場合、hookEvent は null に等しい });
オプション | 以来 | 注記 |
---|---|---|
SAFE_FOR_JQUERY | 2.1.0 | 交換の必要はありません。 |
現在、Github Actions を BrowserStack と組み合わせて使用しています。これにより、サポートされているすべてのブラウザーですべてが計画どおりに進んでいることをコミットごとに確認できるようになります。ここでビルド ログを確認してください: https://github.com/cure53/DOMPurify/actions
npm test
実行すると、さらにローカル テストを実行できます。テストは Node.js v0.6.2 および [email protected] で正常に動作します。
セキュリティを強化するために、関連するすべてのコミットはキー0x24BB6BF4
で署名されます (2016 年 4 月 8 日以降)。
npm i
) npm
正式にサポートします。 GitHub Actions ワークフローは、 npm
を使用して依存関係をインストールするように構成されています。非推奨バージョンのnpm
を使用すると、インストールされている依存関係のバージョンを完全に保証できず、予期しない問題が発生する可能性があります。
ツール インフラストラクチャとの統合には npm run-scripts を利用しています。コードの一貫性を確保するために、ESLint をコミット前フックとして使用します。さらに、書式設定を容易にするために、 rollup
を通じて/dist
アセットを構築するときに prettier を使用します。
これらは npm スクリプトです。
npm run dev
ソースの変更を監視しながらビルドを開始します
npm run test
jsdom と Karma 経由でテストスイートを実行します。
test:jsdom
jsdom を通じてのみテストを実行します
test:karma
、karma を通じてのみテストを実行します。
npm run lint
ESLint (xo 経由) を使用してソースを lint します。
ESLint を渡しやすくするために、prettier を使用してソースをフォーマットするnpm run format
npm run build
UMD モジュールとして縮小および縮小されていないディストリビューション アセットをビルドします。
npm run build:umd
実行して、縮小されていない UMD モジュールのみをビルドします
npm run build:umd:min
、縮小された UMD モジュールのみをビルドします
注: npm run <script>
によってトリガーされるすべての実行スクリプト。
他にも npm スクリプトはありますが、主に CI と統合するためのもの、またはコミットごとにビルド配布ファイルを修正するなどの「プライベート」なものを目的としています。
私たちは