CSS样式中的expression()如何绕过事件属性过滤导致XSS?

打工人尚勤 阅读 19

我在开发评论系统时发现,即使过滤了所有on开头的事件属性,用户提交的CSS代码还是能触发XSS。比如有人写了个这样的样式:

div { width: expression(alert('XSS')); }

测试时发现这段代码在兼容模式下会弹出窗口。之前都是直接过滤onerror/onload等属性,但expression()这种CSS表达式完全没考虑到。现在该怎么修改过滤规则才能同时拦截事件属性和这种危险的CSS特性呢?

我来解答 赞 4 收藏
二维码
手机扫码查看
2 条解答
程序员朝炜
这个问题确实挺棘手的,我之前也碰到过类似的场景。expression() 是 IE 时代的一个老旧特性,虽然现代浏览器基本都废弃了它,但如果你的系统需要兼容旧版 IE,那就得特别小心。

要解决这个问题,我的建议是直接禁用 expression 这个关键字。你可以在过滤规则里加上对它的检测,比如在处理用户提交的 CSS 时,检查是否存在类似 expression 的字符串。如果发现就直接拒绝保存或者移除相关代码。

具体实现的话,可以写一个正则表达式来匹配 expression 和它的内容。比如这样:

function sanitizeCss(css) {
// 匹配 expression(...) 并移除
return css.replace(/expressions*(.*?)/gi, '');
}


这个函数会找到所有形如 expression(...) 的内容并把它清空。不过要注意,正则表达式虽然能解决大部分情况,但它不是万能的。如果你的系统允许更复杂的 CSS 输入,最好还是结合专门的 CSS 解析库来做进一步的安全处理。

另外,我还建议你在服务端和客户端同时做校验。服务端用来拦截恶意输入,客户端用来实时提醒用户哪些内容不被允许。双重保险总归更靠谱一些。

最后再说一句,其实最好的办法是完全禁止用户提交自定义 CSS。如果你的需求允许,可以改成让用户选择预定义的样式模板,这样既安全又省心。毕竟,开放 CSS 输入的风险实在太大了,防不胜防啊!
点赞 1
2026-02-18 16:17
极客慧利
expression() 是 IE 特有的 CSS 表达式功能,能在样式里执行 JS,确实是个经典的 XSS 向量。你只过滤 on 开头的事件属性是不够的,因为这玩意根本不在 HTML 属性里触发,而是藏在 CSS 里面。

要彻底堵住,得从两头下手:一是输入时过滤或移除 expression,二是避免使用不安全的内联样式处理。

最直接的办法是在过滤 CSS 时正则干掉 expression(不区分大小写):

cssText = cssText.replace(/expressions*([^)]*)/gi, '');


但注意别漏了换行或空格绕过的情况,比如 expre ssion(alert()) 这种拆分写法。建议先压缩空白再匹配:

cssText = cssText.replace(/s+/g, ' ').replace(/expressions*(.*?)/gi, '');


更稳一点的做法是直接禁止用户提交完整 CSS,改用白名单字段控制样式,比如只允许 { color: #xxx } 这种基础属性。

另外别忘了 -moz-binding、behavior:url() 这些也能触发 XSS,一并过滤掉。

最后建议把 user-content 的 style 标签全干掉,或者用 CSP 做兜底,style-src 'unsafe-inline' 能不用就别用。这波优化一下,基本就能封死了。
点赞 2
2026-02-12 21:12