文章总结: 这篇文章介绍了一种绕过CORS预检请求的CSRF攻击技术,通过设置Content-Type为text/plain将请求标记为简单请求,避免触发OPTIONS预检。尽管请求体包含JSON数据,浏览器不会触发预检,而多数后端框架仍能正确解析JSON数据,使攻击者能绕过CORS限制执行CSRF攻击。 综合评分: 88 文章分类: WEB安全,漏洞分析,渗透测试
不触发预检的 CSRF 攻击:Content-Type:text/plain 的魔法
原创
Pwn1
漏洞集萃
2025年12月21日 13:40 山东
免责声明 本公众号所发布的文章内容仅供学习与交流使用,禁止用于任何非法用途。
我们都知道一些站点会设计 CORS,这就有可能让我们的 CSRF 攻击无法奏效。
然而我们也知道,CORS 的检测和拦截动作是由浏览器实现的,那么只要我们搞清楚 CORS 拦截的逻辑,就可以绕过它。
简单请求
简单请求 是指满足以下所有条件的请求:
方法
使用其中一种允许的方法:
- •
GET - •
HEAD - •
POST
Header
除了用户代理自动设置的标头(例如 Connection、User-Agent 或禁止的请求标头)之外,唯一允许手动设置的标头是 CORS 安全列表请求标头,它们是:
- •
Accept - •
Accept-Language - •
Content-Language - •
Content-Type - •
Range(仅限单个范围标头值,例如bytes=256-或bytes=127-255)
Content-Type 限制
Content-Type 还必须是以下指定的媒体类型(只允许以下类型/子类型组合):
- •
application/x-www-form-urlencoded - •
multipart/form-data - •
text/plain
额外限制
-
• 对于
Accept、Accept-Language、Content-Language和Content-Type的值: -
• 不能包含 CORS-unsafe 请求头字节(包括禁止的控制字符,如 0x00-0x1F 中的大多数、HTTP newline bytes,以及某些特殊字符)。
-
• 值也只能包含有限的允许字节:数字 (0-9)、大小写字母 (A-Z, a-z)、空格以及特定标点符号(如 *, , – . ; =)。
-
• 无领先/尾随的 HTTP tab 或 space。
-
• 所有 CORS-safelisted 请求头的值总字节长度不得超过 1024 字节(超过则视为非简单请求)。
-
•
Range头(如使用)必须仅包含单个范围值(例如bytes=0-1023),且符合简单范围头规范。
参考:https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS#simple_requests
OPTIONS 预检请求
OPTIONS 预检 是现代浏览器实现 CORS 规范的一部分(写死在浏览器里面了,无论服务器是否设定 CORS,都会默认执行)。
触发 OPTIONS 预检的条件
- • 跨源 + 简单请求 → 不触发预检
- • 跨源 + 非简单请求 → 触发预检
如何通过 text/plain 绕过 CORS?
我们只需要在构造 payload 的时候全程使用简单请求,那么就可以规避 CORS 的限制(当然这里不讨论 CSRF token 的场景)。
示例 1:使用表单
<form method="POST" action="https://target.com/change-email">
<input type="hidden" name="email" value="[email protected]">
<input type="hidden" name="csrf_token" value=""> <!-- 可以为空或伪造 -->
<input type="submit" value="点我">
</form>
示例 2:使用 fetch
fetch("https://target.com/api/update", {
method: "POST",
headers: {
"Content-Type": "text/plain"
},
body: JSON.stringify({ email: "[email protected]" })
});
原理说明:
- • 这里的paylaod将
Content-Type设定为text/plain,那么浏览器久会认为这是一个简单请求。 - • 在这样的情况下,即使
body里实际是 JSON 数据(比如{"email":"[email protected]"}),浏览器也不会因为 body 的格式而触发预检,毕竟它只看Content-Type头。 - • 于此同时,很多后端框架(比如 Express、Spring、Django 等)通常会自动解析 JSON 格式的 body,无论
Content-Type是什么,只要 body 是有效的 JSON 字符串,后端就会正常处理他。
觉得本文内容对您有启发或帮助? 点个关注➕,获取更多深度分析与前沿资讯!
👉 往期精选
攻防演练中的“降维打击”:逃逸出内网边界的影子资产与SaaS供应链挖掘
谷歌登录也防不住?实战劫持 GIS SDK 实现无感账号接管
【漏洞挖掘Tips】一种新的 GraphQL 绕过角度
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:漏洞集萃 Pwn1《不触发预检的 CSRF 攻击:Content-Type:text/plain 的魔法》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论