CSRF(跨站请求伪造)
跨站请求伪造 (Cross-Site Request Forgery, CSRF),也被称为 One Click Attack 或者 Session Riding ,通常缩写为CSRF,是一种对网站的恶意利用。尽管听起来像XSS,但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
攻击原理
利用的是同源策略的漏洞。
攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
攻击示例
- 受害者登录A网站,并且保留了登录凭证(Cookie)
- 攻击者引诱受害者访问B网站
- B网站向A网站发送了一个请求(伪造请求的方式),浏览器请求头中会默认携带 A 网站的 Cookie
- A 网站服务器收到请求后,经过验证发现用户是登录了的,所以会处理请求
常见的CSRF攻击类型
GET类型的CSRF
GET类型的CSRF利用非常简单,只需要一个HTTP请求,一般会这样利用:
<img src="http://bank.example/withdraw?amount=10000&for=hacker" >
<img src="http://bank.example/withdraw?amount=10000&for=hacker" >
在受害者访问含有这个img的页面后,浏览器会自动向
http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker发出一次HTTP
请求。bank.example就会收到包含受害者登录信息的一次跨域请求。
POST类型的CSRF
这种类型的CSRF利用起来通常使用的是一个自动提交的表单,如:
<form action="http://bank.example/withdraw" method="POST">
<input type="hidden" name="account" value="boob" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
<form action="http://bank.example/withdraw" method="POST">
<input type="hidden" name="account" value="boob" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。
POST类型的攻击通常比GET要求更加严格一点,但仍并不复杂。任何个人网站、博客,被黑客上传页面的网站都有可能是发起攻击的来源,后端接口不能将安全寄托在仅允许POST上面。
链接类型的CSRF
链接类型的CSRF并不常见,比起其他两种用户打开页面就中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击
<a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" target="_blank"> 领红包 <a/>
<a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" target="_blank"> 领红包 <a/>
CSRF的特点
- 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
- 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。
CSRF防范
由上面对CSRF的介绍我们知道了,CSRF通常发生在第三方域名,并且CSRF攻击者不能获取到受害者的cookie等信息,只是借用他们的登录状态来伪造请求。所以我们可以针对这两点来制定防范措施
同源检测
既然CSRF大多来自第三方网站,那么我们就直接禁止第三方域名(或者不受信任的域名)对我们发起请求。
在HTTP协议中,每一个异步请求都会携带两个Header,用于标记来源域名:
- Origin Header
- Referer Header
这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。 服务器可以通过解析这两个Header中的域名,确定请求的来源域。同时服务器应该优先检测 Origin。为了安全考虑,相比于 Referer,Origin 只包含了域名而不带路径。
CSRF Token
- 在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。CSRF Token 其实就是服务器生成的随机字符串,然后将该字符串植入到返回的页面中,通常是放到表单的隐藏输入框中,这样能够很好的保护 CSRF Token 不被泄漏;
- 当浏览器再次发送请求的时候,就需要携带这个 CSRF Token 值一起提交;
- 服务器验证 CSRF Token 是否一致;从第三方网站发出的请求是无法获取用户页面中的 CSRF Token 值的。
给 Cookie 设置合适的 SameSite
当从 A 网站登录后,会从响应头中返回服务器设置的 Cookie 信息,而如果 Cookie 携带了 SameSite=strict 则表示完全禁用第三方站点请求头携带 Cookie,比如当从 B 网站请求 A 网站接口的时候,浏览器的请求头将不会携带该 Cookie。
- Samesite=Strict,这种称为严格模式,表明这个 Cookie 在任何情况下都不可能作为第三方 Cookie
- Samesite=Lax,这种称为宽松模式,比 Strict 放宽了点限制:假如这个请求是这种请求(改变了当前页面或者打开了新页面)且同时是个GET请求,则这个Cookie可以作为第三方Cookie。(默认)
- None 任何情况下都会携带;