用innerHTML显示用户评论时怎么防XSS?样式转义后全乱了

一宁宁 阅读 66

我在做论坛帖子展示功能时,用

渲染用户提交的内容,结果测试时发现能注入脚本。后来改用转义函数把<符号替换成&lt;,但用户写的带CSS样式的评论就显示成纯文本了。

比如用户输入:


重要公告

转义后样式完全失效,直接显示原始HTML标签。有没有既能防XSS又保留合法样式的办法?用了DOMPurify还是会出现样式丢失的情况…

我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
Mr-艳青
Mr-艳青 Lv1
试试这个方法:别手动转义标签,用 DOMPurify 配合白名单策略就行。你之前说用了 DOMPurify 样式丢了,大概率是没配对规则。

默认情况下 DOMPurify 会删掉 style 属性和内联样式,所以用户写的 这种自然不生效。你需要开启 ALLOW_STYLE 并指定允许的 CSS 属性。

安装完 DOMPurify 后这么写:

import DOMPurify from 'dompurify';

const clean = DOMPurify.sanitize(dirtyHTML, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'u', 'p', 'br', 'span'],
ALLOWED_ATTR: ['style'],
ADD_URI_SAFE_ATTR: ['target'], // 如果需要支持链接
});

document.getElementById('comment').innerHTML = clean;


但光这样还不够安全,因为攻击者还能在 style 里塞 expression() 或 url(javascript:) 这种恶意内容。建议加个过滤函数限制允许的 CSS 属性值:

DOMPurify.addHook('uponSanitizeElement', (el) => {
if (el.tagName === 'SPAN' && el.style) {
const validProps = ['color', 'font-weight', 'text-decoration'];
validProps.forEach(prop => {
if (el.style[prop] && /expression|url|javascript/i.test(el.style[prop])) {
el.style.removeProperty(prop);
}
});
}
});


另外提醒一点,如果用户发的是 Markdown,最好前端统一转成 HTML 再净化,别让他们直接写带样式的 HTML,不然管理起来太难控制。

这套组合拳下来,既能防住常见 XSS,又能保留基础排版样式,我们项目里就这么干的。
点赞 1
2026-02-09 14:02
书生シ雯婷
DOMPurify 干净又安全,配个白名单保留样式:

const cleanHTML = DOMPurify.sanitize(userInput, { ALLOWED_TAGS: ['b', 'i', 'em', 'strong'], ALLOWED_ATTR: [] });
element.innerHTML = cleanHTML;


自定义允许的标签和属性,既防 XSS 又保留合法样式,搞定。
点赞 6
2026-01-29 14:09