文章总结: 本文揭示利用CSS文件或JS模块绕过Referer校验实现CSRF攻击的新方法。核心在于strict-origin-when-cross-origin策略下,子资源请求的Referer记录的是发起请求文档的origin,而非用户当前页面。攻击者通过上传恶意CSS或JS到目标站,诱导浏览器发起带目标站自身Referer的请求,从而绕过校验。文章提供两种变体利用链及实战检测清单,建议关注文件上传功能并评估SameSite上下文影响。 综合评分: 85 文章分类: WEB安全,漏洞分析,渗透测试,红队
一个 CSS 文件,掀翻 Referer 防线
Ots安全
2026年9月17日 12:41 广东
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
威胁简报
恶意软件
漏洞攻击
一、先说结论:你信错了 Referer
Referer 校验的底层假设只有一句话:只有我自己网站的页面,才能发出带着我家域名的请求。
听起来没毛病,对吧?
问题出在浏览器身上。它悄悄改了 Referer 的”署名规则”,而大多数人根本没细看过这份规则。🎯
Chrome、Firefox、Safari 现在的默认引用策略,都叫 strict-origin-when-cross-origin。它的行为分三种:
-
同源请求
:Referer 带完整 URL,路径参数一个不少
-
跨源请求
:Referer 只带 origin(协议 + 主机 + 端口)
-
HTTPS 降级到 HTTP
:Referer 干脆不发
图1:strict-origin-when-cross-origin 策略下 Referer 的三种取值(本文自制示意图)
但真正致命的不是这三分支,而是另一句话:
Referer 记录的,是”发起这次请求的那份文档”的 origin,不是”用户此刻正在看的那个页面”的 origin。
再读一遍这句话。这两者平时是同一个东西,所以你从没察觉区别。
可一旦发起请求的,是一个被链接进来的子资源——比如一份 CSS 文件、一个 JS 模块——事情就完全变了味。
二、变体一:上传一个 CSS,让目标站自己给自己发请求
来走一遍这条利用链。⚔️
假设目标站 B 有两个特点:
- 有一个改状态的接口(比如发帖),只靠 Referer 校验防护
- 允许用户上传文件,且文件按
Content-Type: text/css原样返回
攻击者的操作步骤如下:
第一步:上传一份精心构造的 CSS 到 B。文件内容里写一条 url(),指向 B 那个改状态的接口。
第二步:B 把这份 CSS 当静态文件提供出去,响应头是 text/css。
第三步:注意,这里是最妙的一步——攻击者不去找 B 上的注入点,而是直接在自己的恶意页面 A 里加一行:
<link rel="stylesheet" href="https://B.com/file/xxx.css">
第四步:受害者打开 A 页面。浏览器跑去 B 那里拉取这份 CSS 并解析,CSS 里的 url() 随之触发一次发往 B 的请求。
第五步:关键来了。这份 CSS 的”户籍”在 B,所以浏览器给这次请求打的 Referer 是 B 自己的 origin。
B 的校验逻辑一看:referer.startsWith('https://B.com/') ✅ 通过。
请求放行,状态被改掉。整条链跑完,攻击者在 B 上连一行 HTML 都没碰过。🤯
图2:CSS 变体利用链——攻击者全程只在自己的页面动手(本文自制示意图)
研究员实测了两个细节,值得记下:
-
Content-Type 卡得很死
:他专门写了个应用测了两千多种 Content-Type,浏览器肯当作样式表加载的,只有
text/css这一种。这是这条链仅有的一个硬门槛。 -
兼容性
:Chrome 和 Firefox 上都能打,Safari 行为略有出入。
三、变体二:JS 模块,四种 Content-Type 随便挑
第二条链思路一样,只是把样式表换成了 JavaScript 模块。📦
HTML 规范里写得明明白白:一个文档加载了模块脚本,模块又去加载下级脚本时,下级请求的 Referer 用的是模块自己的 URL。
和 CSS 完全一个路数:
// 上传到目标站的 JS 文件内容,就这一行import"https://B.com/add-post?content=pwned"
攻击者页面里同样只加一行:
<scripttype="module"src="https://B.com/files/xxx.js"></script>
浏览器拉取模块、执行 import、请求发往 B,Referer 依然是 B 自己的。校验继续形同虚设。
这条链比 CSS 版实用得多,原因就在上图这个对比里👇
图3:CSS 变体只认一种类型,JS 模块变体认四种(本文自制示意图)
text/javascript、application/javascript、application/ecmascript、text/ecmascript——四种都行。
想想看:一个文件上传功能,返回四种 JS 类型之一的概率,和刚好返回 text/css 的概率,差了可不是一点半点。🎯
四、泼盆冷水:Cookie 这道坎
写到这里,你可能觉得天塌了。先别慌,把边界说清楚。🧊
这两条链的请求都是跨站发起的,而现代浏览器的 SameSite Cookie 策略默认不带 Cookie。也就是说——
需要登录态才能操作的接口,按上面这套打法是打不动的。
它目前能改掉的,只是那些不需要身份的公开状态。
但研究员也指出了升级路径:如果你能在目标站自己的页面、或者它的子域上完成这个 <link> / <script> 的注入,请求就落进了 SameSite 上下文,Cookie 跟着就带上了。JS 变体还有个额外门槛——需要目标返回带反射 origin 的 Access-Control-Allow-Credentials: true,这种 CORS 错配在子域上恰恰很常见。
到这里,一个”只能 prove 概念的 PoC”就变成了带着受害者会话的真实 CSRF。
五、实战 Checklist:测之前先问自己两个问题
给做渗透测试和安全评审的同学,把原文的方法论压成一张可以带走的清单。✅
遇到一个用 Referer 校验防护状态变更接口的站点,先做这件事:
把”用户可控制响应 Content-Type 的文件上传功能”列为绕过原语。
然后用两个问题判断能走多远:
-
能不能进入 SameSite 或子域上下文?
能——影响升级为带会话的真实 CSRF;不能——止步于无 Cookie 的状态篡改
-
(JS 变体)目标是否返回带反射 origin 的凭证放行头?
是——带 Cookie 的跨源请求畅通无阻
参考:
https://afine.com/blogs/bypassing-referer-based-csrf-with-strict-origin-when-cross-origin
END
公众号内容都来自国外等平台- 搜索的内容通过结合编写 –
提供整洁 – 广告已关
公众号 | AnQuan7 (Ots安全)
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Ots安全 《一个 CSS 文件,掀翻 Referer 防线》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论