Vue3 中使用 DOMPurify 对渲染动态 HTML 进行安全净化处理

发布于:2025-09-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

在 Vue 3 应用中渲染动态 HTML 内容时,安全风险不容忽视。DOMPurify 是一款强大的工具,能帮你有效抵御 XSS 攻击。下面我来为你讲解如何在 Vue 3 中使用 DOMPurify。

🛡️ Vue 3 中使用 DOMPurify 防御 XSS 攻击

1. 为什么需要 DOMPurify

在 Vue 3 中使用 v-html 指令直接渲染用户提供的 HTML 内容时,存在执行恶意脚本的风险(XSS 攻击)。DOMPurify 是一个开源的基于 DOM 的快速 XSS 净化工具,它通过解析递归元素节点来净化 HTML,输出安全的 HTML 内容。

2. 安装与基础用法

安装 DOMPurify

bash

npm install dompurify

基本净化使用

在 Vue 3 组件中,你可以这样使用 DOMPurify:

vue

<template>
  <div>
    <h2>净化后的HTML内容:</h2>
    <div v-html="sanitizedHtml"></div>
  </div>
</template>

<script>
import { defineComponent, ref, computed } from 'vue';
import DOMPurify from 'dompurify';

export default defineComponent({
  setup() {
    // 示例:可能不安全的HTML输入
    const rawHtml = ref('<p>Hello, <a href="https://example.com">World</a>!</p><img src="x" οnerrοr="alert(1)">');
    
    // 使用计算属性实时净化HTML
    const sanitizedHtml = computed(() => {
      return DOMPurify.sanitize(rawHtml.value);
    });

    return {
      sanitizedHtml
    };
  }
});
</script>

效果说明

上述代码中,原始的 rawHtml 包含一个带有 onerror 属性的 img 标签,这是一种常见的 XSS 攻击向量。经过 DOMPurify 净化后,onerror 等危险属性会被移除,从而使其变得安全。

3. 高级配置与用法

DOMPurify 允许你通过配置选项自定义净化规则,以满足不同的安全需求。

使用配置选项

你可以定义一个配置对象来指定允许的标签和属性:

javascript

import DOMPurify from 'dompurify';

const config = {
  // 只允许这些HTML标签
  ALLOWED_TAGS: ['p', 'a', 'b', 'i', 'em', 'strong'],
  // 只允许这些HTML属性
  ALLOWED_ATTR: ['href', 'title', 'target'],
  // 允许自定义URI的协议
  ALLOWED_URI_REGEXP: /^(https?|ftp):/i
};

const dirtyHtml = '<p>Hello, <a href="https://example.com" target="_blank" οnclick="alert(1)">World</a>!</p>';
const cleanHtml = DOMPurify.sanitize(dirtyHtml, config);
// 输出: <p>Hello, <a href="https://example.com" target="_blank">World</a>!</p>
// 注意:onclick 等危险属性已被移除

使用钩子(Hooks)

DOMPurify 的钩子系统允许你在净化过程中进行更细粒度的控制。例如,你可以阻止特定的属性:

javascript

DOMPurify.addHook('uponSanitizeAttribute', function (node, data) {
  // 示例:阻止所有JavaScript文件的URL
  const regex = /^https?:\/\/.*\.js$/;
  if (data.attrName === 'src' && node.nodeName === 'IMG' && regex.test(data.attrValue)) {
    // 移除该属性
    data.keepAttr = false;
  }
});

4. 查看被移除的内容

在进行安全审计或调试时,你可能需要知道 DOMPurify 移除了哪些内容:

javascript

const dirtyInput = '<script>alert("XSS")</script><p>Safe content</p>';
const clean = DOMPurify.sanitize(dirtyInput);

// 查看被移除的节点
console.log(DOMPurify.removed);
// 可能会输出: [{element: script, attribute: null, reason: "not allowed"}]

请注意,DOMPurify.removed 主要用于调试,不建议在生产环境中依赖它进行业务逻辑判断。

5. 与其他 Vue 特性结合

与响应式数据结合

通常,你会将 DOMPurify 与 Vue 的响应式系统(如 refcomputed)结合使用:

vue

<template>
  <div>
    <textarea v-model="userInput" placeholder="输入HTML内容"></textarea>
    <div v-html="sanitizedUserInput"></div>
  </div>
</template>

<script>
import { defineComponent, ref, computed } from 'vue';
import DOMPurify from 'dompurify';

export default defineComponent({
  setup() {
    const userInput = ref('');

    const sanitizedUserInput = computed(() => {
      return DOMPurify.sanitize(userInput.value);
    });

    return {
      userInput,
      sanitizedUserInput
    };
  }
});
</script>

使用自定义指令

为了更方便地在模板中使用,你可以创建一个自定义指令:

javascript

// main.js 或类似文件
import { createApp } from 'vue';
import App from './App.vue';
import DOMPurify from 'dompurify';

const app = createApp(App);

app.directive('safe-html', (el, binding) => {
  el.innerHTML = DOMPurify.sanitize(binding.value);
});

app.mount('#app');

在组件中使用自定义指令:

vue

<template>
  <div v-safe-html="rawHtml"></div>
</template>

6. 服务端渲染(SSR)注意事项

在 Nuxt.js 等 SSR 环境中,由于 window 对象在服务端不可用,你需要动态导入 DOMPurify 或使用兼容的包装器:

javascript

import DOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';

const window = new JSDOM('').window;
const purify = DOMPurify(window);

const clean = purify.sanitize(dirtyHtml);

7. 安全最佳实践

虽然 DOMPurify 提供了强大的客户端保护,但安全应该是多层次的:

  • 首选文本插值:对于非富文本内容,优先使用 {{ }} 插值或 v-text,它们会自动转义 HTML。

  • 原则:仅允许必要的标签和属性。

  • 服务器端净化不要仅仅依赖客户端净化。在将内容存储到数据库之前,也应在服务器端进行类似的净化和验证。

  • 内容安全策略 (CSP):实施严格的 CSP 作为额外的安全层,以减轻潜在的 XSS 影响。

  • 保持更新:定期更新 DOMPurify 库以确保免受最新威胁。

8. 替代方案

在某些情况下,可以考虑其他方案:

  • 专用的富文本编辑器组件:使用如 TipTap、Quill 或 Tiptap 等组件,它们通常内置了输出安全 HTML 的机制。

  • Vue 的渲染函数或 JSX:对于非常动态的 UI,使用这些方法可以更安全地构建 DOM 结构。

总结

DOMPurify 是 Vue 3 应用中处理不安全 HTML 并防御 XSS 攻击的强力工具。通过其简单的 API 和灵活的配置,它可以满足多种安全需求。关键在于牢记安全需要多层防御,切勿完全依赖客户端净化。