我正在使用一个需要字符串的 Vue 组件。我喜欢在字符串中使用模板值,但当然应该是 XSS 安全的。
这是不安全的,因为 this.name
是不安全的。我可以使用 NPM 包对名称进行 html 编码,但我更喜欢使用 Vue。
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
name: { type: String, required: false },
},
methods: {
showModal() {
this.$buefy.dialog.confirm({
title: 'myTitle',
message: `<p>Hello ${this.name}</p>`, // unsafe - possible XSS!
cancelText: 'Cancel',
confirmText: 'OK',
type: 'is-success',
onConfirm: async () => {
// something
},
});
},
},
});
</script>
这是使用的 Buefy 组件的问题,如文档所示 here:
我创建了一个新组件,在本例中我将其命名为 ModalMessage.Vue
<template>
<p>Hello {{name}}</p>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
name: { type: String, required: true },
},
});
</script>
然后我喜欢在 Typescript 中将 ModalMessage.Vue 渲染为 string
:
<script lang="ts">
import Vue from 'vue';
import ModalMessage from 'ModalMessage.vue';
export default Vue.extend({
props: {
name: { type: String, required: false },
},
methods: {
showModal() {
this.$buefy.dialog.confirm({
title: 'myTitle',
message:, // todo render ModalMessage and pass name prop
cancelText: 'Cancel',
confirmText: 'OK',
type: 'is-success',
onConfirm: async () => {
// something
},
});
},
},
});
</script>
如何呈现 ModalMessage.Vue 并将名称道具传递给 string
?
我很确定这是可能的 - 我过去见过。不幸的是,我无法在网络或 StackOverflow 上找到它。我只能找到关于渲染模板 from 字符串的问题,但我不需要 - 它需要是 to 字符串。
答案 0 :(得分:1)
恕我直言,您真正的问题是“如何将 Buefy 的 Dialog 组件与用户提供的内容一起使用并在 XSS 方面保持安全”
所以您想要创建一些 HTML,在该 HTML 内容中包含一些用户提供的内容 (this.name
) 并将其显示在对话框中。您是对的,将未经过滤的用户输入放入 message
的 Dialog
参数是不安全的(如 Buefy docs 中明确指出)
但您的“所需设置”似乎没有必要复杂。恕我直言,最简单的方法是使用(记录不足)事实,即 Buefy message
配置对象的 Dialog
参数可以是 VNode 的 Array
而不是字符串。它的文档很差,但是从源 here 和 here 中可以很清楚地看出,如果您传递 VNode 的数组,Buefy 会将该内容放入 Dialogs 默认插槽中,而不是使用 v-html
呈现它(这是危险的部分)
在 Vue 中获得 Array
的 VNode
的最简单方法是使用插槽...
所以组件:
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
methods: {
showModal() {
this.$buefy.dialog.confirm({
title: 'myTitle',
message: this.$slots.default, // <- this is important part
cancelText: 'Cancel',
confirmText: 'OK',
type: 'is-success',
onConfirm: async () => {
// something
},
});
},
},
});
</script>
它的用法:
<MyDialog>
<p>Hello {{name}}</p>
</MyDialog>
或
<MyDialog>
<ModalMessage :name="name" />
</MyDialog>
在这两种情况下,如果 name
包含任何 HTML,它将是 encoded by Vue
Here 是上述技术的简单演示(使用纯 JS - 而不是 TS)
答案 1 :(得分:0)
试试这个。
<script lang="ts">
import Vue from 'vue';
import ModalMessage from 'ModalMessage.vue';
export default Vue.extend({
props: {
name: { type: String, required: false },
},
methods: {
showModal() {
const message = new Vue({
components: { ModalMessage },
render: h => h('ModalMessage', { name: this.name })
})
message.$mount()
const dialog = this.$buefy.dialog.confirm({
title: 'myTitle',
message: [message._vnode],
cancelText: 'Cancel',
confirmText: 'OK',
type: 'is-success',
onConfirm: async () => {
// something
},
});
dialog.$on('hook:beforeDestroy', () => {
message.$destroy()
});
},
},
});
</script>
源代码:
演示: