sanitize-htmlのドキュメントを翻訳

vue.js

サニタイズで利用するsanitize-htmlの翻訳をしました。

翻訳対象は下記になります。

目次

sanitize-html

sanitize-htmlは、明確なAPIを備えたシンプルなHTMLサニタイザーを提供します。

sanitize-htmlは寛容です。CKEditorやその他のリッチテキストエディタで作成されたものなどのHTMLフラグメントをクリーンアップするのに適しています。これは、Wordからコピーして貼り付けるときに不要なCSSを削除する場合に特に便利です。

sanitize-htmlを使用すると、許可するタグと、それらの各タグに許可される属性を指定できます。

タグが許可されていない場合、タグの内容は破棄されません。これにはいくつかの例外があります。これについては、以下の「許可されていないタグの内容全体を破棄する」セクションで説明します。

不十分に閉じられた要素の構文pimgクリーンアップされます。

hrefhttp属性は、、、、およびURLのみが含まhttpsれていることを確認するために検証されます。相対URLも許可されます。属性についても同様です。ftpmailtosrc

ホスト名をフィルタリングすることにより、特定のURLをsrciframeタグに許可することもサポートされています。

HTMLコメントは保持されません。さらに、すべてsanitize-htmlのテキストコンテンツをエスケープします。これは、アンパサンド、大なり記号、および小なり記号が同等のHTML文字参照(-> 、->など)に変換されることを意味します。さらに、属性値では、引用符もエスケープされます(-> )。&&amp;<&lt;"&quot;

要件

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-htmlparserセキュリティが目標である場合は、オプションを除いて、変更するのではなくデフォルトを使用することをお勧めし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

禁止されたタグの内容をすべて破棄すること

通常、いくつかの例外を除き、タグが許可されていない場合、その中のすべてのテキストが保存され、その中の許可されたタグも保存されます。

例外はある。stylescripttextareaoption


このリストを置き換える場合、例えば、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.

ぎゅう
WEBエンジニア
渋谷でWEBエンジニアとして働く。
LaravelとVue.jsをよく取り扱い、誰でも仕様が伝わるコードを書くことを得意とする。
先輩だろうがプルリクにコメントをして、リファクタしまくる仕様伝わるコード書くマン
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次
閉じる