前端安全审计时如何防止CSS注入风险?
最近在做项目的安全审计,发现有个用户自定义主题的功能,允许传入CSS字符串动态应用样式。我担心这里会有CSS注入漏洞,比如用户输入恶意代码破坏页面或窃取数据。虽然我用了DOMPurify处理HTML,但对CSS这块不太确定该怎么防护。
目前我是直接把用户输入的CSS插到<style>标签里,像这样:
.user-theme {
background: url('javascript:alert(1)');
color: red;
}
测试时发现某些浏览器居然会执行javascript:伪协议!有没有安全的方式来解析或过滤用户提交的CSS?或者应该完全禁止这种动态样式功能?
标签中确实存在风险,特别是当CSS中包含javascript:这样的伪协议时。解决这个问题的方法有几种,我们可以结合使用来提高安全性。下面我会详细说明每一步怎么做,以及背后的原理。
1. 使用白名单验证
最基础也是最安全的方法是使用白名单来验证和过滤用户输入的CSS。只允许特定的CSS属性和值通过。这样做可以有效防止任何未授权的脚本执行。
原理
通过预先定义允许的CSS属性和它们的合法值范围,我们可以在接收到用户输入后,逐个检查这些属性是否在白名单内,值是否符合预期。只有符合标准的CSS会被应用到页面上。
实现
我们可以用一个简单的JavaScript对象来存储允许的属性和值:
2. 使用CSS-in-JS库
另一种方法是利用CSS-in-JS库,这些库通常会自动处理CSS注入的问题,因为它会生成唯一的类名,并且只允许通过预定义的方式添加样式。
原理
CSS-in-JS库将样式与JavaScript代码紧密结合,这样可以更好地控制哪些样式能够被应用。由于样式是通过代码而不是字符串动态插入的,攻击者很难注入恶意代码。
实现
例如,使用Styled Components这个流行的CSS-in-JS库:
首先安装Styled Components:
然后在你的React组件中使用它:
这种方法的好处是,所有的样式都会经过JavaScript层的处理,确保只有安全的属性和值会被应用。
3. 完全禁止动态样式
如果以上方法都不能满足需求,最彻底的解决方案是完全禁止用户自定义样式。虽然这可能会影响用户体验,但从安全的角度来看,这是最可靠的选择。
总结
总的来说,处理CSS注入问题需要谨慎对待。通过白名单验证可以有效阻止大多数恶意代码,而CSS-in-JS库则提供了一种现代且安全的方式来处理动态样式。如果你的应用对安全有极高的要求,甚至可以考虑完全禁用用户自定义样式功能。
希望这些建议能帮助你解决这个问题。记得在实现过程中,一定要多测试,确保没有遗漏任何可能的安全漏洞。
你发现的确实是个安全问题。CSS里的
url()在某些浏览器(尤其是旧版IE)和特定场景下确实能执行js代码,现代浏览器虽然默认禁止了,但风险依然存在——比如通过expression()(IE旧版)或者利用CSS属性窃取数据。最稳妥的方案是别让用户直接写CSS字符串,改用白名单机制。我之前项目里是这么干的:
把用户可自定义的样式拆成具体的配置项,比如允许用户选背景色、字体大小这些,而不是开放完整的CSS字符串。然后在代码里把这些值赋给CSS变量:
这样用户只能选预设的颜色值,你可以在后端做个白名单列表,永远不让用户直接碰CSS语法。
如果你实在需要支持用户自定义样式,可以用Google的
css-sanitizer库来过滤,它会移除危险属性和函数。不过这库挺重的,而且保不齐有绕过,我个人不推荐。还有一个取巧的办法是用iframe的sandbox属性,把用户样式限制在隔离环境里,但这样功能就受限了。
我的建议是:除非产品必须,否则砍掉这个"用户自定义CSS"的功能,改成"用户自定义主题"——预设几套主题让用户选,省心又安全。动态CSS这玩意儿,运维的时候就知道有多头疼了。