Vue中使用v-html时如何避免XSS漏洞?
在Vue项目里用v-html渲染用户输入的内容时,发现输入的alert(1)居然真的弹窗了。我试过用replace替换尖括号,但复杂HTML结构就乱了,怎么安全地处理用户输入避免XSS?
<template>
<div v-html="userContent"></div>
</template>
<script>
export default {
data() {
return { userContent: '<p>测试内容</p><script>alert(1)</script>' }
}
}
</script>
现在直接渲染会导致XSS执行,如果用escape转义又会把所有标签转义成文本,用户正常的带格式内容(比如加粗文字)也会失效,该怎么平衡安全和正常HTML展示?
先说为什么会有XSS漏洞。当你用v-html渲染内容时,Vue会直接把字符串当作HTML插入到DOM里。如果你的字符串里包含了恶意脚本,比如
<script>alert(1)</script>,浏览器就会执行这段脚本。这就是XSS攻击的核心原理:恶意代码被注入并执行。接下来我们要解决的是如何在允许用户输入富文本(比如带格式的内容)的同时,防止恶意代码被执行。这里推荐使用一个专门处理HTML安全的库,比如 DOMPurify。这个库的作用是清理掉HTML中可能引发安全问题的部分,同时保留合法的HTML结构。
下面是具体实现步骤:
第一步,安装 DOMPurify。你可以通过npm安装它:
第二步,在你的Vue组件中引入并使用 DOMPurify 来清理用户输入的内容。代码可以这样写:
第三步,在模板中渲染清理后的内容。修改你的模板代码如下:
这里的关键点是,我们没有直接渲染
userContent,而是通过计算属性sanitizedContent对内容进行了清理。DOMPurify 会移除像<script>这样的危险标签,但会保留像<p>、<b>这样的安全标签,从而既保证了安全性,又不会破坏正常的HTML结构。如果你还需要支持更多的自定义规则,比如只允许某些特定的标签或属性,DOMPurify 也提供了配置选项。比如你可以这样限制只允许
<p>和<b>标签:最后提醒一下,不要试图自己写正则表达式去过滤HTML,因为HTML的复杂性远超你的想象,很容易遗漏一些边缘情况,导致安全漏洞。用专业的库是最靠谱的做法。
总结一下,核心思路就是借助 DOMPurify 来清理用户输入的内容,确保恶意代码被移除,同时保留合法的HTML结构。这样既能防止XSS攻击,又能让用户正常使用富文本功能。
推荐用一个专门处理HTML安全的库,比如DOMPurify。这个库能帮你清理掉恶意脚本,同时保留正常的HTML结构。下面是具体做法:
首先安装DOMPurify:
然后在你的Vue组件里这样用:
模板部分改成:
这里我把处理逻辑放到了computed属性里,这样当userInput变化时会自动重新计算。DOMPurify默认会移除所有危险的标签和属性,比如script、onclick这些,但会保留安全的HTML标签。
我之前试过自己写正则去过滤,结果发现总有漏网之鱼,维护起来也很麻烦。后来换了DOMPurify,感觉省心多了。它还支持配置白名单,如果你有特殊需求可以自定义规则,不过大部分情况下默认配置就够用了。
记得在生产环境还是要保持警惕,最好再加上CSP(内容安全策略)做额外防护。毕竟前端的安全防护多一层总比少一层好。