在前面我们说过,很多时候大部分的系统漏洞都是很难发现的,这时候大部分的黑客就会通过伪造网站,从而变相获取我们的数据。这其中涉及的方式便是CSRF攻击。
CSRF全称Cross Site Request Forgery,即跨站点请求伪造。我们知道,攻击时常常伴随着各种各样的请求,而攻击的发生也是由各种请求造成的。
从前面这个名字里我们可以关注到两个点:一个是“跨站点”,另一个是“伪造”。前者说明了CSRF攻击发生时所伴随的请求的来源,后者说明了该请求的产生方式。所谓伪造即该请求并不是用户本身的意愿,而是由攻击者构造,由受害者被动发出的。
CSRF的攻击过程大致如图:
CSRF攻击存在的道理
一种攻击方式之所以能够存在,必然是因为它能够达到某种特定的目的。比如:通过程序中的缓冲区溢出漏洞,我们可以尝试控制程序的流程,使其执行任意代码;通过网站上的SQL注入漏洞,我们可以读取数据库中的敏感信息,进而获取Webshell甚至获取服务器的控制权等等。而CSRF攻击能够达到的目的是使受害者发出由攻击者伪造的请求,那么这有什么作用呢?
显然,这种攻击的威力和受害者的身份有着密切的联系。说到这儿我们可以思考一下,攻击者之所以要伪造请求由受害者发出,不正是想利用受害者的身份去达到一些目的吗?换句话说,受害者身上有达到这个目的所必需的条件,
而这些必需的条件在Web应用中便是各种各样的认证信息,攻击者就是利用这些认证信息来实现其各种各样的目的。
下面我们先看几个攻击场景。
(1)场景一:
在一个bbs社区里,用户在发言的时候会发出一个这样的GET请求:
#!html GET /talk.php?msg=hello HTTP/1.1 Host: www.bbs.com … Cookie: PHPSESSID=ee2cb583e0b94bad4782ea (空一行)
这是用户发言内容为“hello”时发出的请求,当然,用户在请求的同时带上了该域下的cookie,于是攻击者构造了下面的csrf.html页面:
#!html <html> <img src=http://www.bbs.com/talk.php?msg=goodbye /> </html>
可以看到,攻击者在自己的页面中构造了一个发言的GET请求,然后把这个页面放在自己的服务器上,链接为http://www.evil.com/csrf.html
。之后攻击者通过某种方式诱骗受害者访问该链接,如果受害者此时处于登录状态,就会带上bbs.com域下含有自己认证信息的cookie访问http://www.bbs.com/talk.php?msg=goodbye
,结果就是受害者按照攻击者的意愿提交了一份内容为“goodbye”的发言。
有人说这有什么大不了的,好,我们再看看另一个场景下的CSRF攻击。
(2)场景二:
在一个CMS系统的后台,发出下面的POST请求可以执行添加管理员的操作:
#!html POST /manage.php?act=add HTTP/1.1 Host: www.cms.com … Cookie: PHPSESSID=ee2cb583e0b94bad4782ea; is_admin=234mn9guqgpi3434f9r3msd8dkekwel (空一行) uname=test&pword=test
在这里,攻击者构造了的csrf2.html页面如下:
#!html <html> <form action="/manage.php?act=add" method="post"> <input type="text" name="uname" value="evil" /> <input type="password" name="pword" value="123456" /> </form> <script> document.forms[0].submit(); </script> </html>
该页面的链接为http://www.evil.com/csrf2.html
,攻击者诱骗已经登录后台的网站管理员访问该链接(比如通过给管理员留言等方式)会发生什么呢?当然是网站管理员根据攻击者伪造的请求添加了一个用户名为evil的管理员用户。
通过这些场景我们可以看到,CSRF攻击会根据场景的不同而危害迥异。小到诱使用户留言,大到垂直越权进行操作。这些攻击的请求都是跨域发出,并且至关重要的一点,都是在受害者的身份得到认证以后发生的。
CSRF的防御
要防御CSRF攻击,我们就要牢牢抓住CSRF攻击的几个特点。
首先是“跨域”,我们发现CSRF攻击的请求都是跨域的,针对这一特点,我们可以在服务端对HTTP请求头部的Referer字段进行检查。一般情况下,用户提交的都是站内的请求,其Referer中的来源地址应该是站内的地址。至关重要的一点是,前端的JavaScript无法修改Referer字段,这也是这种防御方法成立的条件。
不过需要说明的是,有的时候请求并不需要跨域,比如我们后面讲到的结合XSS进行攻击的时候,有的时候甚至没有Referer字段…,这些也是使用这种防御方法的弊病所在。
第二点是“伪造”,这也是CSRF攻击的核心点,即伪造的请求。我们来想一下,攻击者为什么能够伪造请求呢?换句话说,攻击者能够伪造请求的条件是什么呢?纵观之前我们伪造的所有请求,无一例外,请求中所有参数的值都是我们可以预测的,如果出现了攻击者无法预测的参数值,那么将无法伪造请求,CSRF攻击也不会发生。基于这一点,可以使用添加验证码和使用一次性token的方式防御此类攻击,但是正如世界上没有完美的系统一样,也没有完美的防御方式,都是在不断的变化与改进当中。
从上面的例子我们可以看出,制造钓鱼网站,理论上可以获取你浏览器保存的几乎所有数据。所以,不信任的网站,不要轻易点击。上面的例子也仅仅只是csrf最最基础的应用,但是如果是此类攻击,也逃不过使用这种方式。只不过会使用这种方式再加各种类型的变种,或结合其他的攻击方式,对其进行攻击。