From 08d339f9c287ce612e8f3bd47de05514d1154602 Mon Sep 17 00:00:00 2001 From: shuaiplus <2327005759@qq.com> Date: Sat, 24 May 2025 20:14:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20DOMPurify=20=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E5=B9=B6=E6=9B=B4=E6=96=B0=20HTML=20=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=87=BD=E6=95=B0=E4=BB=A5=E7=A1=AE=E4=BF=9D=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/js/util.string.js | 30 ++++++++++++++++++++++-------- package-lock.json | 17 +++++++++++++++++ package.json | 1 + 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/client/js/util.string.js b/client/js/util.string.js index cecb190..eb96c84 100644 --- a/client/js/util.string.js +++ b/client/js/util.string.js @@ -1,20 +1,34 @@ +// Use DOMPurify to safely handle HTML content +// 使用 DOMPurify 安全处理 HTML 内容 +import DOMPurify from 'dompurify'; + // Escape HTML special characters // 转义 HTML 特殊字符 export function escapeHTML(str) { if (typeof str !== 'string') return ''; + // 使用替换方法确保 HTML 特殊字符被转义,而不是被移除 + // 这样 会变成 <java> 而不是被删除 return str.replace(/[&<>"']/g, function(c) { return { - '&': '&', // & to & // & 转为 & - '<': '<', // < to < // < 转为 < - '>': '>', // > to > // > 转为 > - '"': '"', // " to " // " 转为 " - '\'': ''' // ' to ' // ' 转为 ' - } [c] - }) + '&': '&', // & 转为 & + '<': '<', // < 转为 < + '>': '>', // > 转为 > + '"': '"', // " 转为 " + "'": ''' // ' 转为 ' + }[c]; + }); } + // Convert text to HTML, preserving line breaks // 将文本转换为 HTML,保留换行符 export function textToHTML(text) { if (typeof text !== 'string') return ''; - return escapeHTML(text).replace(/\n/g, '
') + // 先进行 HTML 转义,然后将换行符替换为
标签 + // 最后使用 DOMPurify 确保结果是安全的 HTML + const escaped = escapeHTML(text); + const withLineBreaks = escaped.replace(/\n/g, '
'); + return DOMPurify.sanitize(withLineBreaks, { + ALLOWED_TAGS: ['br'], // 只允许
标签 + ALLOWED_ATTR: [], // 不允许任何属性 + }); } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 878a240..83b2692 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@dicebear/micah": "^9.2.2", "aes-js": "^3.1.2", "buffer": "^6.0.3", + "dompurify": "^3.2.6", "elliptic": "^6.6.1", "emoji-picker-element": "^1.26.3", "js-chacha20": "^1.1.0", @@ -841,6 +842,13 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/acorn": { "version": "8.14.1", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.1.tgz", @@ -1278,6 +1286,15 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.2.6", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.6.tgz", + "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/domutils": { "version": "3.2.2", "resolved": "https://registry.npmmirror.com/domutils/-/domutils-3.2.2.tgz", diff --git a/package.json b/package.json index cc08e47..5669fcb 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@dicebear/micah": "^9.2.2", "aes-js": "^3.1.2", "buffer": "^6.0.3", + "dompurify": "^3.2.6", "elliptic": "^6.6.1", "emoji-picker-element": "^1.26.3", "js-chacha20": "^1.1.0",