Vueのテンプレート構文の項を読めばわかることですが、v-htmlにはXSSの危険があることがわかります。
危険なコードの例を見てみましょう。
危険なコード
<template>
<div id="app">
<h1>サニタイズなし</h1>
<p>{{ mastache }}</p>
<p v-html="vhtml"></p>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
mastache: 'mastache:<br><a onmouseover=alert(document.cookie)>click me!</a>',
vhtml: 'vhtml:<br><a onmouseover=alert(document.cookie)>click me!</a>'
}
}
}
</script>
このコードを実行すると、以下のような画面が描画され、click meにマウスオーバーしたときに攻撃コードが実行されてしまいます。
v-htmlを利用して描画する項目に、ユーザからの入力が含まれる可能性がある場合は、v-htmlにサニタイズ処理を加えましょう。
以下の例では、sanitize-htmlを利用してVueの共通処理に仕込んで利用しています。
共通処理を設定
import Vue from 'vue'
import App from './App.vue'
import sanitizeHTML from 'sanitize-html'
Vue.prototype.$sanitize = sanitizeHTML
new Vue({
el: '#app',
render: h => h(App)
})
サニタイズを行う
<template>
<div id="app">
<h1>サニタイズなし</h1>
<p>{{ mastache }}</p>
<p v-html="vhtml"></p>
<h1>サニタイズあり</h1>
<p>{{ $sanitize(mastache) }}</p>
<p v-html="$sanitize(vhtml)"></p>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
mastache: 'mastache:<br><a onmouseover=alert(document.cookie)>click me!</a>',
vhtml: 'vhtml:<br><a onmouseover=alert(document.cookie)>click me!</a>'
}
}
}
</script>
これを実行すると、以下のようになります。
sanitize-htmlの初期設定では、aタグで許可される属性にonmouseoverは含まれていませんので、サニタイズされることがわかります。改行タグなどは、そのまま機能していますね。
サンプルコードは以下。
プロジェクトを作るのが面倒だったので、Springのサンプルプロジェクトの中に紛れています。
以上。
参考:
https://github.com/vuejs/vue/issues/6333
https://blog.sqreen.io/xss-in-vue-js/