サニタイズで利用するsanitize-htmlの翻訳をしました。
翻訳対象は下記になります。
sanitize-html
sanitize-htmlは、明確なAPIを備えたシンプルなHTMLサニタイザーを提供します。
sanitize-htmlは寛容です。CKEditorやその他のリッチテキストエディタで作成されたものなどのHTMLフラグメントをクリーンアップするのに適しています。これは、Wordからコピーして貼り付けるときに不要なCSSを削除する場合に特に便利です。
sanitize-htmlを使用すると、許可するタグと、それらの各タグに許可される属性を指定できます。
タグが許可されていない場合、タグの内容は破棄されません。これにはいくつかの例外があります。これについては、以下の「許可されていないタグの内容全体を破棄する」セクションで説明します。
不十分に閉じられた要素の構文p
がimg
クリーンアップされます。
href
http
属性は、、、、およびURLのみが含まhttps
れていることを確認するために検証されます。相対URLも許可されます。属性についても同様です。ftp
mailto
src
ホスト名をフィルタリングすることにより、特定のURLをsrc
iframeタグに許可することもサポートされています。
HTMLコメントは保持されません。さらに、すべてsanitize-html
のテキストコンテンツをエスケープします。これは、アンパサンド、大なり記号、および小なり記号が同等のHTML文字参照(-> 、->など)に変換されることを意味します。さらに、属性値では、引用符もエスケープされます(-> )。&&<<""
要件
sanitize-htmlは、Node.jsでの使用を目的としており、Node10以降をサポートします。そのnpm依存関係はすべて純粋なJavaScriptです。sanitize-htmlは、優れたhtmlparser2
モジュールに基づいて構築されています。
TypeScriptについて
sanitize-htmlはTypeScriptで記述されておらず、直接サポートする予定はありません。ただし、コミュニティでサポートされているタイピング定義があります@types/sanitize-html
。
npm install -D @types/sanitize-html
esModuleInterop=true
ファイルにが設定されていない場合は、次のtsconfig.json
コマンドでインポートする必要があります。
import * as sanitizeHtml from 'sanitize-html';
使用中の質問や問題@types/sanitize-html
は、そのプロジェクトの貢献ガイドラインの指示に従って、そのメンテナに送信する必要があります。
使い方
ブラウザ
最初に考えてください:なぜあなたはそれをブラウザで使いたいのですか?サーバーがブラウザを信頼してはならないことを忘れないでください。サーバー以外の場所でサーバーに保存するためにHTMLをサニタイズすることはできません。
ただし、サニタイズされたHTMLをブラウザにすぐに表示してプレビューしたい場合があります。または、ページが読み込まれるたびにサニタイズ作業を行うようにブラウザに依頼します。あなたがしたい場合はできます!
- パッケージをインストールします。
npm install sanitize-html
または
yarn add sanitize-html
実行してインストールを開始します
sanitize-htmlの2.xバージョンの主な変更点は、ブラウザーで使用できるビルドが含まれなくなったことです。開発者は、他の依存関係と同様に、プロジェクトビルド(webpackなど)にsanitize-htmlを含めることが期待されています。そのため、sanitize-htmlはHTMLで直接リンクする準備ができていませんが、開発者は必要に応じてより簡単に処理できるようになりました。
ブラウザでビルドして他のプロジェクトのJavascriptとリンクすると、フロントエンドコードのHTML文字列をサニタイズするために使用できます。
import sanitizeHtml from 'sanitize-html';
const html = "<strong>hello world</strong>";
console.log(sanitizeHtml(html));
console.log(sanitizeHtml("<img src=x onerror=alert('img') />"));
console.log(sanitizeHtml("console.log('hello world')"));
console.log(sanitizeHtml("<script>alert('hello world')</script>"));
Node (Recommended)
コンソールからモジュールをインストールします。
npm install sanitize-html
モジュールをインポートします。
// In ES modules
import sanitizeHtml from 'sanitize-html';
// Or in CommonJS
const sanitizeHtml = require('sanitize-html');
JavaScriptアプリで使用します。
const dirty = 'some really tacky HTML';
const clean = sanitizeHtml(dirty); // 第二引数にオプション設定を追加します
これにより、許可されたタグと属性のデフォルトのリストが通過できるようになります。それは素晴らしいセットですが、おそらくあなたが望むものではありません。
// 超限定的なタグと属性のセットのみを許可する
const clean = sanitizeHtml(dirty, {
allowedTags: [ 'b', 'i', 'em', 'strong', 'a' ],
allowedAttributes: {
'a': [ 'href' ]
},
allowedIframeHostnames: ['www.youtube.com']
});
Boom!
allowedTags: [
"address", "article", "aside", "footer", "header", "h1", "h2", "h3", "h4",
"h5", "h6", "hgroup", "main", "nav", "section", "blockquote", "dd", "div",
"dl", "dt", "figcaption", "figure", "hr", "li", "main", "ol", "p", "pre",
"ul", "a", "abbr", "b", "bdi", "bdo", "br", "cite", "code", "data", "dfn",
"em", "i", "kbd", "mark", "q", "rb", "rp", "rt", "rtc", "ruby", "s", "samp",
"small", "span", "strong", "sub", "sup", "time", "u", "var", "wbr", "caption",
"col", "colgroup", "table", "tbody", "td", "tfoot", "th", "thead", "tr"
],
disallowedTagsMode: 'discard',
allowedAttributes: {
a: [ 'href', 'name', 'target' ],
// 現在、デフォルトではimg自体を許可していませんが
// これらの属性は、もしそうするならば、意味をなすでしょう。
img: [ 'src', 'srcset', 'alt', 'title', 'width', 'height', 'loading' ]
},
// これらの多くは、デフォルトで表示されないようになっています。
selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
// 許可するURLスキーム
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto', 'tel' ],
allowedSchemesByTag: {},
allowedSchemesAppliedToAttributes: [ 'href', 'src', 'cite' ],
allowProtocolRelative: true,
enforceHtmlBoundary: false
一般的な使用例
「私はあなたのセットが好きですが、もう1つタグを追加したいと思います。便利な方法はありますか?」
もちろん
const clean = sanitizeHtml(dirty, {
allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ])
});
allowedTags
またはを指定しない場合allowedAttributes
、デフォルトのリストが適用されます。したがって、本当に空のリストが必要な場合は、リストを指定してください。
「すべてのタグまたはすべての属性を許可したい場合はどうすればよいですか?」
単純!allowedTags
オプションを終了または除外する代わりに、allowedAttributes
一方または両方を次のように設定しますfalse
。
allowedTags: false,
allowedAttributes: false
「タグを許可したくない場合はどうすればよいですか?」
シンプル!とに設定allowedTags
します。[]allowedAttributes{}
allowedTags: [],
allowedAttributes: {}
「許可されていないタグを破棄するのではなくエスケープしたい場合はどうすればよいですか?」
(デフォルト)に設定disallowedTagsMode
するとdiscard
、許可されていないタグは破棄されます。個々のサブタグが許可されているかどうかに応じて、テキストコンテンツまたはサブタグは引き続き含まれます。
に設定disallowedTagsMode
するescape
と、許可されていないタグは破棄されるのではなくエスケープされます。テキストまたはサブタグはすべて正常に処理されます。
に設定disallowedTagsMode
するrecursiveEscape
と、許可されていないタグは破棄されるのではなくエスケープされ、許可されているかどうかに関係なく、すべてのサブタグに同じ処理が適用されます。
「一部の属性で特定の値のみを許可したい場合はどうすればよいですか?」
allowedAttributesで属性を設定するときは、属性名と許可される値の配列を持つオブジェクトを使用するだけです。次の例では、
sandbox="allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-scripts"
は
sandbox="allow-popups allow-scripts"
となっています。
allowedAttributes: {
iframe: [
{
name: 'sandbox',
multiple: true,
values: ['allow-popups', 'allow-same-origin', 'allow-scripts']
}
]
}
multiple: true
の場合,複数の許容値を空白で区切って同じ属性に出現させることができる。そうでなければ,属性は,許可された値のうちの1つだけに正確に一致しなければならない。
属性のワイルドカード
*
ワイルドカードを使用して、特定のプレフィックスを持つすべての属性を許可できます。
allowedAttributes: {
a: [ 'href', 'data-*' ]
}
また、タグの名前としてasを使用して*
、リストされた属性をすべてのタグに対して有効にすることができます。
allowedAttributes: {
'*': [ 'href', 'align', 'alt', 'center', 'bgcolor' ]
}
追加オプション
許可されたCSSクラス
特定の要素で特定のCSSクラスを許可する場合は、allowedClasses
オプションを使用して許可できます。その他のCSSクラスはすべて破棄されます。
これは、class
属性がその要素で許可されていることを意味します。
// CSSクラスの制限されたセットのみを許可し、pタグにのみ許可する
const clean = sanitizeHtml(dirty, {
allowedTags: [ 'p', 'em', 'strong' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ]
}
});
allowedAttributes
と同様に、*
を使用して特定の接頭辞を持つクラスを許可したり、*
をタグ名として使用して、リストされたクラスを任意のタグに対して有効にすることができます。
さらに、正規表現もサポートされています。
allowedClasses: {
p: [ /^regex\d{2}$/ ]
}
許可されたCSSスタイル
特定の要素に特定の CSS スタイルを許可したい場合は、allowedStyles
オプションで行います。希望する属性を正規表現のオプションとして、与えられた属性の配列の中で宣言するだけです。特定の要素は、global (*
)属性から allowlisted 属性を継承します。それ以外のCSSクラスは破棄されます。
また、allowedAttributes
を使用して、関連する要素の style 属性を有効にする必要があります。そうでなければ、この機能が発揮されることはありません。
正規表現を作成する場合、^
と$
を忘れてはいけません。”そして、これだけ “と言わなければならない。
インラインスタイル内のURLは、正規表現以外の方法でフィルタリングされることはありません。
const clean = sanitizeHtml(dirty, {
allowedTags: ['p'],
allowedAttributes: {
'p': ["style"],
},
allowedStyles: {
'*': {
// Match HEX and RGB
'color': [/^#(0x)?[0-9a-f]+$/i, /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/],
'text-align': [/^left$/, /^right$/, /^center$/],
// Match any number with px, em, or %
'font-size': [/^\d+(?:px|em|%)$/]
},
'p': {
'font-size': [/^\d+rem$/]
}
}
});
<html></html>
タグの外側のテキストを破棄する。
テキスト編集アプリケーションの中には、WebアプリケーションにコピーできるようなHTMLを生成するものがあります。これらの文字には、htmlタグの終了後に望ましくない制御文字が含まれることがあります。デフォルトでは、sanitize-htmlはこれらの文字を破棄せず、代わりにサニタイズされた文字列で返します。この動作は、enforceHtmlBoundaryオプションを使用して変更することができます。
このオプションをtrueに設定すると、html
タグの境界の外側–<html>
タグの前と</html>
タグの後–のすべての文字を破棄するようにsanitize-htmlに指示します。
enforceHtmlBoundary: true
htmlparser2オプション
sanitize-htmlはに基づいて構築されていhtmlparser2
ます。デフォルトでは、渡されるオプションは。のみですdecodeEntities: true
。パーサーオプションを使用して、渡すオプションを設定できます。
セキュリティ上の注意:parser
設定を変更すると危険な場合があります。特に、decodeEntities: false
既知のセキュリティ上の懸念があり、で使用した場合の設定のすべての可能な組み合わせに対して完全なテストスイートが存在するわけではありませんsanitize-html
。parser
セキュリティが目標である場合は、オプションを除いて、変更するのではなくデフォルトを使用することをお勧めしlowerCaseTags
ます。
const clean = sanitizeHtml(dirty, {
allowedTags: ['a'],
parser: {
lowerCaseTags: true
}
});
可能なオプションの完全なリストについては、 htmlparser2wikiを参照してください。
変換
属性を追加または変更したい場合はどうなりますか?あるタグを別のタグに変換したい場合はどうなりますか?問題ありません、それは簡単です!
最も簡単な方法(すべてのol
タグをul
タグに変更します):
const clean = sanitizeHtml(dirty, {
transformTags: {
'ol': 'ul',
}
});
最も高度な使用法:
const clean = sanitizeHtml(dirty, {
transformTags: {
'ol': function(tagName, attribs) {
// 私独自のカスタムマジックはこちら
return {
tagName: 'ul',
attribs: {
class: 'foo'
}
};
}
}
});
タグ名の代わりにワイルドカードを指定して、*
すべてのタグを変換できます。
タグを変更したり、いくつかの属性を追加したりする単純なケースには十分なヘルパーメソッドもあります。
const clean = sanitizeHtml(dirty, {
transformTags: {
'ol': sanitizeHtml.simpleTransform('ul', {class: 'foo'}),
}
});
simpleTransform
ヘルパーメソッドには3つのパラメーターがあります。
simpleTransform(newTag, newAttributes, shouldMerge)
最後のパラメータ (shouldMerge
) は、デフォルトで true
に設定されています。true
の場合、simpleTransform
は現在の属性を新しい属性 (newAttributes
) とマージします。false
の場合、すべての既存の属性は破棄されます。
また、タグのテキスト内容を追加・変更することも可能です。
const clean = sanitizeHtml(dirty, {
transformTags: {
'a': function(tagName, attribs) {
return {
tagName: 'a',
text: 'Some text'
};
}
}
});
例えば、アンカーテキストが欠落したlink要素を変換することができます。
<a href="http://somelink.com"></a>
アンカーテキストを含むリンクに変換します
<a href="http://somelink.com">Some text</a>
フィルター
不要なタグを除去するためのフィルター機能を提供することができます。
例えば、次のような空のa
タグを削除する必要があるとします。
<a href="page.html"></a>
以下のようなフィルタで実現できる。
sanitizeHtml(
'<p>This is <a href="http://www.linux.org"></a><br/>Linux</p>',
{
exclusiveFilter: function(frame) {
return frame.tag === 'a' && !frame.text.trim();
}
}
);
コールバックに供給されるframe
オブジェクトは、以下の属性を提供します。
tag
:タグ名、つまり'img'
。attribs
:タグの属性、つまり{ src: "/path/to/tux.png" }
。text
:タグのテキストコンテンツ。mediaChildren
:自己完結型メディアを表す可能性が高い即時子タグ(例img
、、、、)。完全なリストについては、の変数を参照してください。videopictureiframemediaTagssrc/index.js
tagPosition
:結果文字列内のタグの位置のインデックス。
提供されているフィルター機能を使用して、すべてのテキストコンテンツを処理することもできます。3つのドットの代わりに省略記号が必要だとします。
<p>some text...</p>
以下のようなフィルタで実現できる。
sanitizeHtml(
'<p>some text...</p>',
{
textFilter: function(text, tagName) {
if (['a'].indexOf(tagName) > -1) return //Skip anchor tags
return text.replace(/\.\.\./, '…');
}
}
);
textFilter
メソッドに渡されたテキストは、HTMLとして安全に表示できるように既にエスケープされていることに注意してください。マークアップを追加したり、textFilter
にエンティティエスケープシーケンスを使用したりすることができます。
Iframe フィルター
iframe
タグを許可したいが、通過させるドメインを制御したい場合、iframe
ソースとして許可するホスト名の配列および/またはドメインの配列を指定することができます。このホスト名は、sanitize-html関数の引数として渡されるoptionsオブジェクトのプロパティとなります。
これらの配列は関数に渡された html と照合され、許可されたホスト名またはドメインをオブジェクトに含む src url
だけを返します。渡された html の url は、埋め込まれた iframe
として正しくフォーマットされている (有効なホスト名) 必要があり、そうでなければモジュールは iframe
から src
を切り取ります。
許可するドメインと一緒に、有効なホスト名を必ず渡してください(例)。
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
allowedIframeDomains: ['zoom.us']
また、iframeのソースとして相対URLを許可するかどうかを指定することもできます。
allowIframeRelativeUrls: true
指定しない場合、ホスト名やドメインのフィルタがなければ相対URLはデフォルトで許可されますが、ホスト名やドメインのフィルタがある場合はデフォルトで削除されることに注意してください。
src属性だけでなく、iframeタグも許可されている必要があることを忘れないでください。
例えば
const clean = sanitizeHtml('<p><iframe src="https://www.youtube.com/embed/nykIhs12345"></iframe><p>', {
allowedTags: [ 'p', 'em', 'strong', 'iframe' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ],
},
allowedAttributes: {
'iframe': ['src']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
});
は、安全な場所として通過します。
const clean = sanitizeHtml('<p><iframe src="https://www.youtube.net/embed/nykIhs12345"></iframe><p>', {
allowedTags: [ 'p', 'em', 'strong', 'iframe' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ],
},
allowedAttributes: {
'iframe': ['src']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
});
または
const clean = sanitizeHtml('<p><iframe src="https://www.vimeo/video/12345"></iframe><p>', {
allowedTags: [ 'p', 'em', 'strong', 'iframe' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ],
},
allowedAttributes: {
'iframe': ['src']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
});
は空のiframeタグを返します。
任意のレベルのサブドメインを許可したい場合は、allowedIframeDomains
にドメインを指定することができます。
// このiframeマークアップは、安全なものとして通過されます。
const clean = sanitizeHtml('<p><iframe src="https://us02web.zoom.us/embed/12345"></iframe><p>', {
allowedTags: [ 'p', 'em', 'strong', 'iframe' ],
allowedClasses: {
'p': [ 'fancy', 'simple' ],
},
allowedAttributes: {
'iframe': ['src']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
allowedIframeDomains: ['zoom.us']
});
Script Filters
iframeと同様に、許可リストで指定されたドメインでスクリプトタグを許可することができます。
const clean = sanitizeHtml('<script src="https://www.safe.authorized.com/lib.js"></script>', {
allowedTags: ['script'],
allowedAttributes: {
script: ['src']
},
allowedScriptDomains: ['authorized.com'],
})
スクリプトタグは、許可リストに記載されたホスト名でも許可することができます。
const clean = sanitizeHtml('<script src="https://www.authorized.com/lib.js"></script>', {
allowedTags: ['script'],
allowedAttributes: {
script: ['src']
},
allowedScriptHostnames: [ 'www.authorized.com' ],
})
許可されるURLスキーム
デフォルトでは、href
, src
などが許可されている場合、以下のURLスキームを許可しています。
[ 'http', 'https', 'ftp', 'mailto' ]
必要であれば、これをオーバーライドすることができます。
sanitizeHtml(
// データURLに含まれる小さな有効な透過GIF
'<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />',
{
allowedTags: [ 'img', 'p' ],
allowedSchemes: [ 'data', 'http' ]
}
);
また、特定のタグにのみスキームを許可することも可能です。
allowedSchemes: [ 'http', 'https' ],
allowedSchemesByTag: {
img: [ 'data' ]
}
また、デフォルトで許可されている、現在のプロトコルを使用して別のサイトにアクセスするためのプロトコル相対URL(//で始まる)の使用を禁止することができます。
allowProtocolRelative: false
禁止されたタグの内容をすべて破棄すること
通常、いくつかの例外を除き、タグが許可されていない場合、その中のすべてのテキストが保存され、その中の許可されたタグも保存されます。
例外はある。style
, script
, textarea
, option
このリストを置き換える場合、例えば、noscript
タグの中にあるものをすべて破棄する場合は、nonTextTags
オプションを使用します。
nonTextTags: [ 'style', 'script', 'textarea', 'option', 'noscript' ]
このオプションを使用する場合、リスト全体を記述する責任があることに注意してください。これにより、textarea
の内容を保持する力を得ることができます。
script
タグとstyle
タグを除いて、コンテンツは適切にエスケープされます。script
タグとstyle
タグのどちらかを許可すると、XSS攻撃を受ける可能性があります。sanitize-html
は、これらのタグが許可されている場合、警告を記録します。
許可されないタグをどうするか選択する
テキストを破棄したり、テキストだけを残す代わりに、コンテンツ全体のエスケープを可能にすることもできます。
disallowedTagsMode: 'escape'
これは、下記のコンテンツを
<disallowed>content</disallowed>
次に変換します
<disallowed>content</disallowed>
有効な値は次のとおりです。discard’ (デフォルト)、 ‘escape’ (タグをエスケープする)、 ‘recursiveEscape’ (タグとその内容をすべてエスケープする)。
ディープネスティングの制限
nestingLimit
オプションにより、文書内のHTMLタグの深さを制限することができます。
nestingLimit: 6
これにより、ユーザーは6レベル以上のタグをネストすることができなくなります。それ以上の深さのタグは、それらが許可されていないかのように正確に取り除かれます。これは、適切な場合には通常の方法でテキストが保存されることを意味することに注意してください。
ApostropheCMSについて
sanitize-htmlは、Node.jsで構築されたオープンソースのコンテンツ管理システムApostropheCMSで使用するために、P’unk Avenueで作成されました。もし、あなたがsanitize-htmlを気に入ったなら、ぜひApostropheCMSをチェックしてみてください。
Support
Feel free to open issues on github.
コメント