Vue.js v-html
v-html
- 预期:
string
详细
更新元素的 innerHTML
。
注意:内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译 。
如果试图使用 v-html
组合模板,可以重新考虑是否通过使用组件来替代。
在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用
v-html
,永不用在用户提交的内容上。
在单文件组件里,
scoped
的样式不会应用在v-html
内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对v-html
的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局<style>
元素手动设置类似 BEM 的作用域策略。
示例
<div v-html="html"></div>
参考
xss 攻击演示
<template>
<div id='app'>
<div v-html='html'></div>
</div>
</template>
<script>
export default {
name:"app",
data(){
return {
html:'<img src="https://www.axihe.com" onerror="alert(666)">'
}
}
}
</script>
运行之后由于 src 地址对应的资源找不到,会触发 img 标签的 error 事件,最终 alert 弹框。这便是一个最简单的 xss 攻击。
解决 html 指令存在的 xss 漏洞问题
通常我们处理 xss 攻击会使用一个 xss 的 npm 包来过滤 xss 攻击代码。
所以我们要做的就是给指令的 value 包上一层 xss 函数。有同学可能会问,我们在业务代码里使用 xss 函数处理也行。是的可以,但是我们不能保证团队每一个成员都会使用 xss 函数处理。
作为前端的架构师,我们需要从项目整体的考虑来处理这类问题,不能指望通过规范来约束团队成员。
在编译前会将我们从 vue-loader 传入的 compilerOptions.directives 和 baseOptions.directives 进行了合并。
这样我们就能覆盖 html 指令。
- 引入 xss 包并挂载到 vue 原型上
import xss from 'xss';
Vue.prototype.xss = xss
- 在 vue.config.js 中覆写 html 指令
chainWebpack: config => {
config.module
.rule("vue")
.use("vue-loader")
.loader("vue-loader")
.tap(options => {
options.compilerOptions.directives = {
html(node, directiveMeta) {
(node.props || (node.props = [])).push({
name: "innerHTML",
value: `xss(_s(${directiveMeta.value}))`
});
}
};
return options;
});
}
这样我们就从源头解决了 html 指令存在的潜在 xss 攻击。
具体参考参考:https://juejin.im/post/5d5924a0e51d4561fc620a46
可能存在的问题
此外某些情况下,使用{{{}}}符号仍然不能解析 html 标签,但 v-htm 指令却可以,可能是 Vue.js 存在的 bug 。
参考:https://blog.csdn.net/farYang/article/details/53011703