CSRF
介绍
CSRF(Cross-Site Request Forgery)的意思是跨站点请求伪造,也被称作一键攻击或会话控制。其原理是攻击者构造网站后台某个功能接口的请求地址,诱导用户去点击或使用特殊方法让该请求地址自动加载。用户在登录状态下这个请求被服务器接收后会被误以为是用户合法的操作。对于GET形式的接口地址可轻易被攻击。对于POST形式的接口地址也不是百分百安全,攻击者可以诱导用户进入带Form表单并且可用POST方式提交参数的页面。
一个典型的CSRF有着如下的流程:
- 受害者登陆a.com,并保留了登录凭证(Cookie)
- 攻击者引诱受害者访问了b.com
- b.com向a.com发送了一个请求:a.com/act=xx,浏览器会默认待a.com的Cookie
- a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求
- a.com以受害者的名字执行了act=xx
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,并让a.com执行了自己定义的操作
CSRF几种类型
1.GET类型的CSRF
受害者访问包含这个img的页面后,浏览器会自动向发出一次http请求,网站会收到包含受害者登录信息的一次跨域请求。
2.POST类型的CSRF
这种类型的CSRF利用起来通常使用的是一个自动提交的表单,访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。
POST类型的攻击通常比GET要求更严格一些,但不能将安全寄托在仅允许POST上面。
3.链接类型你的CSRF
链接类型的CSRF并不常见,比起其他两种用户打开页面就中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片里嵌入恶意链接,或者以广告的形式诱导用户中招。
<a href="https://test.com">重磅消息!</a>
CSRF的特点
- 攻击一般发起在第三网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作,而不是直接窃取数据
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是冒用
- 跨站请求可以用各种方式:图片url,超链接,CORS,Form提交等。部分提交方式可以直接嵌入第三方论坛、文章中,难以进行追踪。
CSRF通常是跨域的,因为外域通常更容易被攻击者掌控,但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。
防护策略
上文中讲了CSRF的两个特点:
- 通常发生在第三方域名。
- 攻击者不能获取到Cookie等信息,只是使用。
针对这两点,可以专门制定防护策略:
- 阻止不明外域的访问:同源检测,Samsite Cookie
- 提交时要求附加本域才能获取的信息:Origin Header,Referer Header
同源检测
在http协议中,每一个异步请求都会携带两个Header,用于标记来源域名:
- Origin Header
- Referer Header
这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容,服务器可以通过解析这两个Header中的域名,确定请求的来源。
使用Origin Header确定来源域名
如果origin存在,那么直接使用origin中的值来确定来源域名就可以。但是origin在一下两种情况并不存在:
- IE11同源策略:IE11不会在跨域CORS请求上添加Origin,Referer将仍然是唯一的标识,最根本的原因是因为IE11对同源的定义和其他浏览器不同。
- 302重定向:在302重定向之后origin不包含在重定向的请求中,因为origin可能会被认为是其他来源的敏感信息。对于302重定向的情况来说都是定向到新的服务器上的url,因此浏览器不想将Origin泄漏到新的服务器上。
使用Referer Header确定来源域名
根据http协议,在http头中有一个字段叫referer,记录了该http请求的来源地址。
对于Ajax请求,图片和script等资源的请求,referer为发起请求的页面地址。
对于页面跳转,referer为打开页面历史记录的前一个页面地址。
因此我们使用referer中链接的origin部分可以得知请求的来源域名。
将referer policy的策略设置成same-origin,对于同源的链接和引用,会发送referer,referer的值为host不带path;跨域访问则不携带referer。
设置referer policy的方法有三种:
- 在CSP设置。
- 页面头部增加meta标签。
- a标签增加referrerpolicy属性。
在以下情况里referer没有被携带或者不可信:
- IE6、IE7使用window.location.href=url进行界面的跳转,会丢失referer。
- IE6、IE7使用window.open,也会缺失referer。
- HTTPS页面跳转到HTTP页面时,所有浏览器referer都丢失。
- 点击flash上到达另一个网站时,referer的情况比较杂乱,不太可信。