在一次项目中,挖掘了一些CSRF漏洞,将细节提交给客户后,发生了一些有趣的交互,这里简单的先把他叫为薛定谔的CSRF,对其深入了解了一下,且听我细细道来。
故事背景是对一个项目整体过了一遍后,大部分功能模块是一些越权之类的问题没有发现CSRF,只有对接的一个第三方插件有CSRF的问题,将相关报告提交给了客户。故事的开端是复测的时候,当我用Google浏览器复现CSRF的时候,已经无法复现成功的时候,复测报告对CSRF的漏洞就填写了已修复。然后客户提出了疑问。如下:
既然并没有修复,那为什么复现不了了呢?薛定谔的CSRF?
那不行,开始对CSRF进行鞭挞,自己对相关接口进行了反复测试,都已经无法复现,发现携带cookie,但提示401错误,如下:
如果拦截数据包,一步一步放包,会发现进行一次302跳转,如下图:
同时发现,数据包中是没有携带cookie的。不行,头好痒,要长脑子了。
和客户同步了相关情况后,客户提出了新的疑问:
这里重新使用Google浏览器进行了测试,打开F12查看数据流观察一下:
这里我们发现,当我们去轻轻的点击了我们构造的测试链接时,浏览器发了四个请求:
详细说一下上面四个请求的流程,首先第一次请求没有携带Cookie,所以会通过OAuth协议去拉取Cookie,这也是最开始咱们进行复测的时候会出现302跳转的原因。最后一次请求用获取的Cookie在次向接口请求,但是请求方法变成了GET,而删除操作的参数是在POST数据包中,并没有提交过来,所以即使接口返回成功,但是并没有删除。
当我正准备提交测试结果,并说明无法复现的时候,老大叫到了我说:“这不是CSRF可以删除吗?你为什么删不掉呢”,我过去瞅了一眼,确实执行并成功删除了,这接口看眼缘?(开玩笑的),老大说他用的是火狐浏览器,那有没有可能是浏览器的缘故?说干就干,使用浏览器进行复现,再次查看数据流:
我们发现火狐浏览器,不需要通过层层跳转的方式,而是直接获取cookie 并直接删除,请求方法还是POST,所以删除成功了。
为什么会有这么情况呢?通过查阅资料,发现这和浏览器的安全机制有关系。
从Chrome 51开始,浏览器的Cookie新增加了一个SameSite属性,用来防止CSRF攻击和用户追踪,该设置当前默认是关闭的,但在Chrome 80之后,该功能默认已开启。SameSite 属性有三个值可以设置
Strict
最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。但是这种情况用户体验不太友好。
Lax
规则稍稍放宽,详情如下表:
请求类型 | 示例 | 正常情况 | Lax |
---|---|---|---|
链接 | <a href="..."></a> | 发送 Cookie | 发送 Cookie |
预加载 | <link rel="prerender" href="..."/> | 发送 Cookie | 发送 Cookie |
GET 表单 | <form method="GET" action="..."> | 发送 Cookie | 发送 Cookie |
POST 表单 | <form method="POST" action="..."> | 发送 Cookie | 不发送 |
iframe | <iframe src="..."></iframe> | 发送 Cookie | 不发送 |
AJAX | $.get("...") | 发送 Cookie | 不发送 |
Image | <img src="..."> | 发送 Cookie | 不发送 |
None
是关闭SameSite
属性。
调研完毕后,将结果同步给了客户:
过了一会儿,客户给了反馈,客户对此比较重视,并从更多维度测试了此问题,这是值得我去学习的一点:
不仅对chrome浏览器是否同源进行了测试,浏览器同样尝试了更多其它的浏览器。在此点个赞。
这篇文章从一次csrf失败的复现引出浏览器安全机制等一系列有趣的事,同时通过这件事也让我发现了自身存在的一些问题,比如不够细节,考虑问题没有从更多方面去考虑。思维不够发散,只停留在问题本身等等。改正自己,持续学习,乐于分享,加油!