Vue3中防御XSS攻击的“特效药”-DOMPurify

一、快速入门

1.1 DOMPurify 概述

  在 JavaScript 开发的世界中,安全性是保护应用程序免受潜在威胁和漏洞的至关重要。在 Vue 3 应用中渲染动态 HTML 内容时,安全风险不容忽视。DOMPurify 是一个开源的基于 DOM 的快速 XSS 净化工具,专门用于净化HTML、MathML和SVG,能有效防御跨站脚本攻击(XSS攻击)。它通过解析递归元素节点来净化 HTML,输出安全的 HTML 内容,能够有效抵御防止XSS攻击。

1.2 DOMPurify 核心思路

  DOMPurify 的核心思想是:不要自己写 HTML 解析器,而是让浏览器来解析

graph LR A["恶意 HTML 字符串"] A-->B["浏览器 DOM 解析器"] B-->C["DOM 树"] C-->D["遍历 DOM 树"] D-->E["检查节点"] E--在白名单-->F1["保留"] E--不在白名单-->F2["删除"] F1-->G["安全的 HTML"] F2-->G

1.3 安装与引入

  可以通过 npm 来安装 DOMPurify 库,命令如下:

bash 复制代码
# 确认安装版本(含嵌套依赖)
npm install dompurify

# 或者
yarn add dompurify

  在需要使用 DOMPurify 的文件中导入 DOMPurify 库,代码如下:

javascript 复制代码
import DOMPurify from 'dompurify';

1.4 基础用法

  使用 DOMPurify 库过滤 HTML 非常简单,可以直接调用 DOMPurify.sanitize() 方法,将需要过滤的HTML字符串作为参数传入,然后它就会返回一个消毒过的版本。比如,在表单的提交中,或者需要根据用户改变html内容的时候,净化字符串,放置隐藏恶意脚本。代码示例如下:

javascript 复制代码
import DOMPurify from 'dompurify';

// 示例:可能不安全的HTML输入
let rawHtml = '<p>Safe content</p><scr' + 'ipt>alert("XSS")</scr' + 'ipt>';
let sanitizedHtml = DOMPurify.sanitize(rawHtml);
console.log('DOMPurify过滤前:', rawHtml)
console.log('DOMPurify过滤后:', DOMPurify.sanitize(html))

  在上面的示例中,我们尝试注入一段 JavaScript 代码。然而,DOMPurify 检测到此并删除它,使得输出的 HTML 代码是安全的。

二、DOMPurify 高级配置

  DOMPurify 不仅支持简单的清洗操作,它还提供了详细的配置选项,使得开发人员能够通过配置选项自定义净化规则,以满足不同的安全需求。

2.1 白名单过滤

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

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

const dirtyHtml = '<p>Hello, <a href="https://example.com" target="_blank" οnclick="alert(1)">World</a>!</p>';
const cleanHtml = DOMPurify.sanitize(dirtyHtml, config);

2.2 自定义钩子

  DOMPurify 支持在净化流程的不同阶段插入自定义逻辑,实现高度定制化的安全策略,允许我们在净化过程中进行更细粒度的控制。

钩子函数 简要说明
beforeSanitizeElements 在清理元素前触发,可用于提前移除某些节点或属性
afterSanitizeElements 对节点进行基础清理之后触发,常用于处理链接安全、图片防盗链、强制 HTTPS
uponSanitizeShadowNode
beforeSanitizeAttributes
afterSanitizeAttributes 在清理属性后触发
beforeSanitizeShadowDOM
afterSanitizeShadowDOM
uponSanitizeElement 当遍历到具体的 HTML 元素时触发,可以用来记录日志、监控被拦截的危险标签
uponSanitizeAttribute 在处理具体属性时触发,常用于校验 URL 协议,防止执行恶意的 JavaScript 代码

  例如,可以阻止特定的属性:

javascript 复制代码
DOMPurify.addHook('uponSanitizeAttribute', (node, data) => {
  if (data.attrName === 'src' && /javascript:/i.test(data.attrValue)) {
    data.keepAttr = false; // 阻止javascript:协议
  }
});

三、最佳实践

3.1 查看被移除的内容

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

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

// 查看被移除的节点
console.log(DOMPurify.removed);

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

3.2 结合Vue响应式数据

  通常,我们还会将 DOMPurify 与 Vue 的响应式系统(如 ref、computed)结合使用:

html 复制代码
<script setup>
import { ref, computed } from 'vue';
import DOMPurify from 'dompurify';

const userInput = ref('');
const sanitizedInput = computed(() => DOMPurify.sanitize(userInput.value));
</script>

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

3.3 使用自定义指令

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

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');

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

html 复制代码
<template>
  <div v-safe-html="rawHtml"></div>
</template>

四、总结

  当今数字时代,安全性在应用程序开发中变得愈发重要。为了确保用户数据的保密性、完整性和可靠性,开发人员需要采取各种措施来应对安全挑战。DOMPurify 是 Vue 3 应用中处理不安全 HTML 并防御 XSS 攻击的强力工具。通过其简单的 API 和灵活的配置,它可以满足多种安全需求。关键在于牢记安全需要多层防御,切勿完全依赖客户端净化。

相关推荐
小小19921 小时前
idea 配置less转化为css
前端·css·less
hhb_6181 小时前
Less嵌套避坑:优先级冲突实战解析
前端·css·less
云水一下2 小时前
Vue.js从零到精通系列(五):全局状态管理——Pinia 核心与实践
前端·javascript·vue.js
ylscode2 小时前
GreatXML BitLocker绕过漏洞深度解析:Windows Defender离线扫描如何被改造成本地提权后门
windows·安全
我不是外星人2 小时前
浅谈我对 AI 发展的看法
前端·ai编程·claude
站斧小威2 小时前
跨境新店养号阶段环境精细化设置技巧
安全
老马聊技术2 小时前
AI对话功能之SpringBoot整合Vue3
vue.js·人工智能·spring boot·后端
甲维斯2 小时前
测一波Kimi K2.7,消耗一周配额!
前端·人工智能·游戏开发
Dick5072 小时前
ROS2 多机器人通用 Driver 层复盘:BaseRobotDriver 到多平台 Mock 切换实现
前端·javascript·机器人