
想象一下,用户在你的网站评论区输入了一段看似普通的文字。这段文字里隐藏了恶意的脚本代码。
当其他用户浏览这个页面时,这段代码就会在他们的浏览器里偷偷执行。攻击者可能偷走用户的登录信息,也可能控制用户的账号,甚至把病毒传播给更多人。
今天,我们就来聊聊怎么在 Vue 3 和 TypeScript 的项目里,给你的富文本编辑器加上一道坚固的“防火墙”,彻底堵住XSS攻击的漏洞。
XSS攻击到底是什么?
简单来说,XSS攻击就是攻击者把恶意代码“注入”到正常的网页里。当其他用户浏览这个被“污染”的网页时,恶意代码就会运行。
在富文本编辑器的场景里,攻击路径通常是这样的:
- 用户A在编辑器里输入内容。他输入的不是普通文字,而是一段夹杂着HTML和JavaScript的代码。
- 你的网站没有对这段内容做安全检查,直接把它保存到了数据库里。
- 用户B打开页面,查看用户A发布的内容。这时,服务器把那段“脏”数据原封不动地发送给用户B的浏览器。
- 用户B的浏览器把这段内容当成正常的网页代码来解析和执行,恶意脚本就这样被激活了。
举个例子,用户可能在评论框里输入这样的内容:
<script>alert('你的信息被偷了!');</script>或者更隐蔽的:
<img src="x" onerror=stealCookie()" />如果这些内容没有被处理,直接显示在页面上,就会立刻执行。
构建我们的安全防线
下面,我们一步步来构建这个安全解决方案。我们会用到 Vue 3 的响应式特性和组合式API,以及 TypeScript 的强类型检查,让我们的代码更健壮、更清晰。
第一步:选择并集成富文本编辑器
市面上有很多优秀的富文本编辑器,比如 Quill、TinyMCE、wangEditor。它们通常都内置了一些基础的安全过滤。但为了绝对的安全,我们不能完全依赖它们。我们要建立自己的第二道、第三道防线。
这里我们以 wangEditor 为例,因为它对Vue 3的支持很好,而且轻量。
- 安装依赖:
npm install @wangeditor/editor @wangeditor/editor-for-vue@next- 创建一个基础的编辑器组件 (RichTextEditor.vue):
<template> <div class="editor-container"> <Toolbar :editor="editorRef" :defaultConfig="toolbarConfig" style="border-bottom: 1px solid #ccc" /> <Editor :defaultConfig="editorConfig" v-model="htmlValue" @onCreated="handleCreated" style="height: 400px; overflow-y: hidden" /> </div></template><script setup lang="ts">import '@wangeditor/editor/dist/css/style.css';import { onBeforeUnmount, shallowRef } from 'vue';import { Editor, Toolbar } from '@wangeditor/editor-for-vue';// 编辑器实例,必须用 shallowRefconst editorRef = shallowRef();// 编辑器内容(HTML字符串)const htmlValue = defineModel<string>('html', { required: true });const toolbarConfig = {};const editorConfig = { placeholder: '请输入内容...', MENU_CONF: {}};// 编辑器创建后的回调函数const handleCreated = (editor: any) => { editorRef.value = editor;};// 组件销毁时,及时销毁编辑器onBeforeUnmount(() => { const editor = editorRef.value; if (editor == null) return; editor.destroy();});</script>现在,我们有了一个可以工作的编辑器。但它输出的 htmlValue 是原始的HTML字符串,直接使用它非常危险。
第二步:DOMPurify
我们不能自己从头写一个HTML过滤器,这太容易出错了。我们应该使用一个久经考验的库:DOMPurify。
DOMPurify 是一个专门用于净化HTML的JavaScript库。它只允许安全的HTML通过,默认配置下就会移除所有脚本和危险属性。
- 安装DOMPurify:
npm install dompurifynpm install -D @types/dompurify # 安装TypeScript类型定义- 创建一个安全的显示组件 (SafeHtmlDisplay.vue):
这个组件专门用来安全地渲染从富文本编辑器来的HTML。
<template> <div class="safe-html" v-html="purifiedHtml"></div></template><script setup lang="ts">import { computed } from 'vue';import DOMPurify from 'dompurify';const props = defineProps<{ html: string;}>();// 核心净化逻辑const purifiedHtml = computed(() => { // 使用DOMPurify进行净化 return DOMPurify.sanitize(props.html, { // 可以在这里添加自定义配置 // 例如:ALLOWED_TAGS: ['p', 'strong', 'em', 'img', 'a'], // 只允许这些标签 // ADD_ATTR: ['target'], // 额外允许的属性 });});</script><style scoped>.safe-html { /* 可以在这里添加样式,限制图片最大宽度等 */}.safe-html img { max-width: 100%; height: auto;}</style>关键点:
- 我们使用 v-html 指令来渲染HTML。
- v-html 的内容是经过 DOMPurify.sanitize() 函数净化后的安全字符串。
- DOMPurify 会递归地检查整个HTML树,移除 <script>、onerror、_javascript: 等所有危险内容。
- 通过 computed 属性,确保每当输入的 html 变化时,都会自动执行净化过程。
第三步:前后端双重校验
前端的安全措施是给好用户的体验,但绝不能作为唯一的安全保障。恶意用户完全可以绕过你的前端页面,直接伪造请求把恶意数据发送给你的服务器。
所以,服务器端必须进行完全相同的安全检查。
第四步:处理用户粘贴的内容
用户经常从其他网站复制内容粘贴到编辑器。这些内容可能包含隐藏的样式、脚本或垃圾代码。我们需要在内容进入编辑器时就进行一次清理。
这可以在编辑器的配置中完成。
// 在 RichTextEditor.vue 的 editorConfig 中const editorConfig: Partial<IEditorConfig> = { // ... 其他配置 MENU_CONF: { // 配置粘贴时的处理 insertImage: { // ... 图片配置 }, }, // 自定义粘贴处理 customPaste: (editor: IDomEditor, event: ClipboardEvent): boolean => { // 获取粘贴的HTML const html = event.clipboardData?.getData('text/html'); if (html) { // 使用DOMPurify清理粘贴的内容 const cleanHtml = DOMPurify.sanitize(html, getSanitizeConfig()); // 将清理后的内容插入编辑器 editor.dangerouslyInsertHtml(cleanHtml); // 阻止默认的粘贴行为 event.preventDefault(); return true; // 表示已处理 } return false; // 使用默认处理 }};写在最后
安全不是一个功能,而是一个过程。对于富文本编辑器这样的高风险功能,我们必须给予最高级别的重视。
通过 Vue 3 + TypeScript + DOMPurify 的组合,我们构建了一套从输入、展示到存储的完整防御方案。
TypeScript帮助我们减少了代码错误,Vue 3的响应式系统让安全净化自动且高效,DOMPurify则提供了行业级的安全保障。
记住这个原则:永远不要信任用户输入的数据。 对任何来自用户的内容,都要进行严格的、多层次的处理和校验。