Vue.jsにsanitize-htmlを導入し、XSS対策をする

vue.js

こちらのsanitize-htmlを利用していきます

まずはインストールです。

npm install sanitize-html

installが完了したら、importします

import sanitizeHtml from 'sanitize-html';

importしたsanitaizeHtmlを利用して、サニタイズします

const dirty = 'some really tacky HTML';
const clean = sanitizeHtml(dirty);

dirtyがサニタイズ前で、sanitizeHtml(dirty)によって、サニタイズされた値を取得できます。

サニタイズの内容はオプションで設定可能です。

sanitizeHtml(サニタイズしたい値, オプション);

オプションのデフォルト設定は、下記です。

// 使用可能なHTMLタグ
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',
// 使用可能なattributes
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: {},

使用可能なタグやattributeやstyleを指定できます。正規表現での指定も可能なので、限定的に適用が可能です。

それでは全体像が見えたところで、sanitaizeHtml.vueを作成して、vueで利用していきます。

<template>
  <div v-html="html" class="ql-editor p-0"></div>
</template>
<script>
import sanitizeHtml from 'sanitize-html';
export default {
  props: {
    propsHtml: {
      type: String,
      required: true,
    },
  },
  data() {
    return {
      html: sanitizeHtml(this.propsHtml, {
        // 使用可能なattributes
        allowedAttributes: {
          '*' : [ 'class' ],
          a: [ 'href', 'name', 'target' ],
          img: [ 'src', 'srcset', 'alt', 'title', 'width', 'height', 'loading'],
          span: ['style'],
        },
        // 使用可能なstyle
        allowedStyles: {
          '*': {
            'color': [/^#(0x)?[0-9a-f]+$/i, /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/],
            'background-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$/],
            'font-size': [/^\d+(?:px|em|%)$/]
          },
        },
        allowedSchemes: [ 'http', 'https' ],
        allowedSchemesAppliedToAttributes: [ 'href' ],
      }),
    }
  },
}
</script>

こちらのcomponentを利用して、下記のようにサニタイズしたい値をpropsで渡せば、サニタイズされたHTMLが表示されます。

<sanitize-html :props-html="html"></sanitize-html>

こちらで以上です。

オプションの箇所で正規表現で指定したクラスやstyleのみを適用できるのは、素晴らしいですよね。

いろいろオプションを試してみると面白そうです

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

コメント

コメントする

目次
閉じる