From 4396c53d795ad4412bf0a64abde4e63d8708c1ca Mon Sep 17 00:00:00 2001 From: webb <822028533@qq.com> Date: Sun, 28 Apr 2024 23:26:04 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dxss=E6=BC=8F=E6=B4=9E?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/render/node/nodeCreateContents.js | 3 +- simple-mind-map/src/utils/xss.js | 46 +++++++++++++++++++ web/src/pages/Edit/components/Count.vue | 7 +-- 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 simple-mind-map/src/utils/xss.js diff --git a/simple-mind-map/src/core/render/node/nodeCreateContents.js b/simple-mind-map/src/core/render/node/nodeCreateContents.js index cd2dd183..b7464dab 100644 --- a/simple-mind-map/src/core/render/node/nodeCreateContents.js +++ b/simple-mind-map/src/core/render/node/nodeCreateContents.js @@ -17,6 +17,7 @@ import { } from '@svgdotjs/svg.js' import iconsSvg from '../../../svg/icons' import { CONSTANTS } from '../../../constants/constant' +import {defenseXSS} from "../../../utils/xss"; // 创建图片节点 function createImgNode() { @@ -148,7 +149,7 @@ function createRichTextNode() { text: text }) } - let html = `
${this.getData('text')}
` + let html = `
${defenseXSS(this.getData('text'))}
` if (!this.mindMap.commonCaches.measureRichtextNodeTextSizeEl) { this.mindMap.commonCaches.measureRichtextNodeTextSizeEl = document.createElement('div') this.mindMap.commonCaches.measureRichtextNodeTextSizeEl.style.position = 'fixed' diff --git a/simple-mind-map/src/utils/xss.js b/simple-mind-map/src/utils/xss.js new file mode 100644 index 00000000..afd92bd2 --- /dev/null +++ b/simple-mind-map/src/utils/xss.js @@ -0,0 +1,46 @@ +/** + * 防御 XSS 攻击,过滤恶意 HTML 标签和属性 + * @param {string} text 需要过滤的文本 + * @returns {string} 过滤后的文本 + */ +export function defenseXSS(text) { + // 初始化结果变量 + let result = text; + + // 使用正则表达式匹配 HTML 标签 + const match = text.match(/<(\S*?)[^>]*>.*?|<.*? \/>/g); + if (match == null) { + // 如果没有匹配到任何标签,则直接返回原始文本 + return text; + } + + // 遍历匹配到的标签 + for (let value of match) { + // 定义白名单属性正则表达式(style、target、href) + const whiteAttrRegex = new RegExp(/(style|target|href)=["'][^"']*["']/g); + + // 定义黑名单href正则表达式(javascript:) + const aHrefBlackRegex = new RegExp(/href=["']javascript:/g); + + // 过滤 HTML 标签 + const filterHtml = value.replace( + // 匹配属性键值对(如:key="value") + /([a-zA-Z-]+)\s*=\s*["']([^"']*)["']/g, + (text) => { + // 如果属性值包含黑名单href或不在白名单中,则删除该属性 + if (aHrefBlackRegex.test(text) || !whiteAttrRegex.test(text)) { + return ""; + } + + // 否则,保留该属性 + return text; + } + ); + + // 将过滤后的标签替换回原始文本 + result = result.replace(value, filterHtml); + } + + // 返回最终结果 + return result; +} \ No newline at end of file diff --git a/web/src/pages/Edit/components/Count.vue b/web/src/pages/Edit/components/Count.vue index 2b752ba1..75bddfa8 100644 --- a/web/src/pages/Edit/components/Count.vue +++ b/web/src/pages/Edit/components/Count.vue @@ -12,7 +12,8 @@