如何将 Buefy 的 Dialog 组件与用户提供的内容一起使用并在 XSS 方面是安全的
How to use Buefy's Dialog component with user provided content and be safe in terms of XSS
Buefy 的 Dialog 组件需要一个 message
属性 - 字符串。根据文档,该字符串可以包含 HTML。我想在字符串中使用模板值,但当然应该是 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,并将 name 属性传递给 string
?
我很确定这是可能的 - 我以前见过。不幸的是,我无法在网络或 Whosebug 上找到它。我只能找到从 from 字符串呈现模板的问题,但我不需要那个 - 它需要是 to 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() {
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>
源代码:
演示:
恕我直言,您真正的问题是 “如何将 Buefy 的对话框组件与用户提供的内容一起使用,并在 XSS 方面是安全的”
所以您想要的是创建一些 HTML,在该 HTML 内容中包含一些用户提供的内容 (this.name
) 并将其显示在对话框中。你是对的,将未经过滤的用户输入放入 Dialog
的 message
参数是不安全的(如 Buefy docs 中明确指出)
但是您的“所需设置”似乎不必要地复杂。恕我直言,最简单的方法是使用(记录不详)事实,即 Buefy Dialog
配置对象的 message
参数可以是 VNode 的 Array
而不是字符串。它的文档很少,但从源代码 here and here 中可以清楚地看出,如果您传递一个 VNode 数组,Buefy 会将这些内容放入 Dialogs 默认插槽中,而不是使用 v-html
渲染它(这是危险的部分)
在 Vue 中获得 Array
of 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)
Buefy 的 Dialog 组件需要一个 message
属性 - 字符串。根据文档,该字符串可以包含 HTML。我想在字符串中使用模板值,但当然应该是 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,并将 name 属性传递给 string
?
我很确定这是可能的 - 我以前见过。不幸的是,我无法在网络或 Whosebug 上找到它。我只能找到从 from 字符串呈现模板的问题,但我不需要那个 - 它需要是 to 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() {
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>
源代码:
演示:
恕我直言,您真正的问题是 “如何将 Buefy 的对话框组件与用户提供的内容一起使用,并在 XSS 方面是安全的”
所以您想要的是创建一些 HTML,在该 HTML 内容中包含一些用户提供的内容 (this.name
) 并将其显示在对话框中。你是对的,将未经过滤的用户输入放入 Dialog
的 message
参数是不安全的(如 Buefy docs 中明确指出)
但是您的“所需设置”似乎不必要地复杂。恕我直言,最简单的方法是使用(记录不详)事实,即 Buefy Dialog
配置对象的 message
参数可以是 VNode 的 Array
而不是字符串。它的文档很少,但从源代码 here and here 中可以清楚地看出,如果您传递一个 VNode 数组,Buefy 会将这些内容放入 Dialogs 默认插槽中,而不是使用 v-html
渲染它(这是危险的部分)
在 Vue 中获得 Array
of 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)