CSRF 跨站请求伪造
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的登录凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
题外话:还有个 SSRF
(Server-Side Request Forgery
)服务器端请求伪造
危害
利用用户登录状态进行操作,如发布留言、盗取用户资金等
攻击类型
GET
类型POST
类型- 链接类型
GET 类型
假设一个可以支付的请求链接为 http://demo.com/pay?amount=10000&for=hacker
,我们将其放入到第三方网站的页面中。
<img src="http://demo.com/pay?amount=10000&for=hacker" />
<img src="http://demo.com/pay?amount=10000&for=hacker" />
用户在访问了 demo.com
网站并登陆后,又点击进入了这个三方网站,这个网站的内容就是上面的一个图片,而图片的 src
地址就是 demo.com
网站的支付链接,如果后端没做来源 referer
限制,就会进入支付操作。
POST 类型
这种类型的 CSRF
通常使用的是一个隐藏的自动提交表单,如:
<form action="http://demo.com/pay" method=POST>
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
<form action="http://demo.com/pay" method=POST>
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
原理与 GET
类型一样,进入这个三方页面就会执行,但他是 POST
提交。
链接
需要用户主动点击链接才会触发。一般在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会使用比较夸张的词语诱骗用户点击,如:
<a href="http://demo.com/pay?amount=1000&for=hacker" taget="_blank">重磅消息!!</a>
<a href="http://demo.com/pay?amount=1000&for=hacker" taget="_blank">重磅消息!!</a>
CSRF 特点
- 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
- 跨站请求可以用各种方式:图片URL、超链接、JSONP、Form 提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。
如何防范
因为 CSRF
通常发生在第三方域名,且攻击者不能获取到用户信息,只是借用他们的登录状态进行请求伪造,所以有以下几种方法:
1. 同源检测
禁止第三方或者非白名单的域名对网站发起请求,服务器可通过请求头的请求来源进行判断:
Origin Header
Referer Header
标明请求来源域名 缺点:Referer
可以被伪造(比如假设浏览器有某些漏洞导致可以篡改referer
);也会屏蔽搜索引擎的链接
2. CSRF Token
- 在浏览器向服务器发起请求时,服务器生成一个
CSRF Token
。CSRF Token
其实就是服务器生成的随机字符串,然后将该字符串植入到返回的页面中,通常是放到表单的隐藏输入框中,这样能够很好的保护CSRF Token
不被泄漏; - 当浏览器再次发送请求的时候,就需要携带这个
CSRF Token
值一起提交; - 服务器验证
CSRF Token
是否一致;从第三方网站发出的请求是无法获取用户页面中的CSRF Token
值的。
缺点:一般用在前后端不分离场景,每个请求都要添加这个 token
,操作繁琐,且在负载均衡时,另一台服务器不存在对应的 session
,就无法验证,可通过 jwt
的 token
生成形式进行改写。
3. 给 Cookie 设置合适的 SameSite
当从 A
网站登录后,会从响应头中返回服务器设置的 Cookie
信息,而如果 Cookie
携带了 SameSite=strict
则表示完全禁用第三方站点请求头携带 Cookie
。比如当从 B
网站请求 A
网站接口的时候,浏览器的请求头将不会携带该 Cookie
。
Samesite=Strict
,严格模式:这个Cookie
只能在自己域名下使用Cookie
Samesite=Lax
,宽松模式(默认项):假如这个请求是这种请求(改变了当前页面或者打开了新页面)且同时是个GET
请求,则这个Cookie
可以作为第三方Cookie
。
4. 双重 Cookie 验证
- 当用户访问网站页面是,向请求域名注入一个 Cookie,内容为随机字符串(例如csrfcookie=v8g9e4ksfhw)
- 在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(接上例POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw)
- 后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝。
优点:
- 无需使用 Session,适用面更广,易于实施。
- Token 储存于客户端中,不会给服务器带来压力。
- 相对于 Token,实施成本更低,可以在前后端统一拦截校验,而不需要一个个接口和页面添加。
缺点:
- Cookie 中增加了额外的字段。
- 如果有其他漏洞(例如XSS),攻击者可以注入 Cookie,那么该防御方式失效。
- 难以做到子域名的隔离。
- 为了确保 Cookie 传输安全,采用这种防御方式的最好确保用整站 HTTPS 的方式,如果还没切 HTTPS 的使用这种方式也会有风险。