如何解决将 Vue 组件/模板渲染为 (html) 字符串 问题
我正在使用一个需要字符串的 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,message:,// todo render ModalMessage and pass name prop
cancelText: 'Cancel',});
</script>
问题
如何呈现 ModalMessage.Vue 并将名称道具传递给 string
?
我很确定这是可能的 - 我过去见过。不幸的是,我无法在网络或 StackOverflow 上找到它。我只能找到关于渲染模板 from 字符串的问题,但我不需要 - 它需要是 to 字符串。
解决方法
恕我直言,您真正的问题是“如何将 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)
,试试这个。
<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',});
dialog.$on('hook:beforeDestroy',() => {
message.$destroy()
});
},});
</script>
源代码:
演示:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。