Nuxt.jsでsanitize-htmlを使ってみる

Nuxt.jsでサニタイズすることがあったので、sanitize-htmlの設定方法をメモ。
sanitize-html はバージョン 2.7.0 を使用しています。

設定方法

Nuxt.jsの環境にパッケージをインストールします。

yarn add sanitize-html

npmの場合は下記になります。

npm install sanitize-html

pluginsディレクトリにsanitize-html.jsを作成します。

import Vue from 'vue';
import sanitizeHTML from 'sanitize-html';

Vue.prototype.$sanitize = sanitizeHTML;

nuxt.config.jsのpluginsに先ほどのファイルパスを追加します。

export default {
  plugins: [
    '@/plugins/sanitize-html'
  ]
}

これで一通りの設定が完了したので、実際に試してみます。

<template>
  <div>
    <h2>サニタイズなし</h2>
    <div v-html="test"></div>
    <h2>サニタイズあり</h2>
    <div v-html="$sanitize(test)"></div>
  </div>
</template>

<script>
export default {
  data(){
    return{
      test:`
        <p class="script" style="color: red;"><a onclick=alert("aaa")>alert</a></p>
        <p><img src="https://cly7796.net/blog/wp-content/uploads/2020/10/nuxtjs.jpg"></p>
        <iframe width="560" height="315" src="https://www.youtube.com/embed/6LXbazi_RHo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
      `
    }
  },
}
</script>

結果は以下のようになり、サニタイズありの方はimgやiframeといったタグやonclick、class、styleなどの属性が除去されました。

<h2>サニタイズなし</h2>
<div>
  <p class="script" style="color: red;"><a onclick="alert(&quot;aaa&quot;)">alert</a></p>
  <p><img src="https://cly7796.net/blog/wp-content/uploads/2020/10/nuxtjs.jpg"></p>
  <iframe width="560" height="315" src="https://www.youtube.com/embed/6LXbazi_RHo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>
<h2>サニタイズあり</h2>
<div>
  <p><a>alert</a></p>
  <p></p>
</div>

sanitize-htmlのドキュメントに記載がありますが、初期設定は以下のようになっているようです。
allowedTagsが許容するタグ、allowedAttributesがタグ毎に許容する属性になります。

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: [ 'src', 'srcset', 'alt', 'title', 'width', 'height', 'loading' ]
},
selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto', 'tel' ],
allowedSchemesByTag: {},
allowedSchemesAppliedToAttributes: [ 'href', 'src', 'cite' ],
allowProtocolRelative: true,
enforceHtmlBoundary: false

先ほどの例でimgとiframeタグを許容したい場合、sanitize-html.jsに設定を追加します。

import Vue from 'vue';
import sanitizeHtml from 'sanitize-html';

sanitizeHtml.defaults.allowedTags = sanitizeHtml.defaults.allowedTags.concat(['img', 'iframe']);

Vue.prototype.$sanitize = sanitizeHtml;

sanitizeHtml.defaults.allowedTags でデフォルトで許容されているタグの取得や設定ができます。

結果は以下のようにimgとiframeが許容されましたが、デフォルトではiframeの属性が許容されていないので、何も表示されません。

<h2>サニタイズなし</h2>
<div>
  <p class="script" style="color: red;"><a onclick="alert(&quot;aaa&quot;)">alert</a></p>
  <p><img src="https://cly7796.net/blog/wp-content/uploads/2020/10/nuxtjs.jpg"></p>
  <iframe width="560" height="315" src="https://www.youtube.com/embed/6LXbazi_RHo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>
<h2>サニタイズあり</h2>
<div>
  <p><a>alert</a></p>
  <p><img src="https://cly7796.net/blog/wp-content/uploads/2020/10/nuxtjs.jpg"></p>
  <iframe></iframe>
</div>

iframeの各属性と、全ての要素のclass属性とstyle属性の許容を試してみます。
先ほどと同様、sanitize-html.jsに設定を追加します。

import Vue from 'vue';
import sanitizeHtml from 'sanitize-html';

sanitizeHtml.defaults.allowedTags = sanitizeHtml.defaults.allowedTags.concat(['img', 'iframe']);
sanitizeHtml.defaults.allowedAttributes['iframe'] = ['*'];
sanitizeHtml.defaults.allowedAttributes['*'] = ['class', 'style'];

Vue.prototype.$sanitize = sanitizeHtml;

これでiframeの各属性とclass属性、style属性の許容ができました。

<h2>サニタイズなし</h2>
<div>
  <p class="script" style="color: red;"><a onclick="alert(&quot;aaa&quot;)">alert</a></p>
  <p><img src="https://cly7796.net/blog/wp-content/uploads/2020/10/nuxtjs.jpg"></p>
  <iframe width="560" height="315" src="https://www.youtube.com/embed/6LXbazi_RHo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>
<h2>サニタイズあり</h2>
<div>
  <p class="script" style="color:red"><a>alert</a></p>
  <p><img src="https://cly7796.net/blog/wp-content/uploads/2020/10/nuxtjs.jpg"></p>
  <iframe width="560" height="315" src="https://www.youtube.com/embed/6LXbazi_RHo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>

他にも色々な設定が行えるので、詳しくはsanitize-htmlのページをご確認ください。

参考サイト

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


コメントが承認されるまで時間がかかります。

2022年6月
 1234
567891011
12131415161718
19202122232425
2627282930