CSRF跨站请求伪造攻击

CSRF跨站请求伪造攻击

简介

CSRF攻击的全称是跨站请求伪造( cross site request forgery)。

CSRF是一种挟制用户在当前已登录的WEB应用程序上执行非本意的操作的攻击方法。

是一种对网站的恶意利用,尽管听起来跟XSS跨站脚本攻击有点相似,但事实上CSRF与XSS差别很大,XSS利用的是站点内的信任用户,而CSRF则是通过伪装来自受信任用户的请求来利用受信任的网站。你可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义向第三方网站发送恶意请求。 CRSF能做的事情包括利用你的身份发邮件、发短信、进行交易转账等,甚至盗取你的账号。

攻击原理

CSRF跨站请求伪造攻击_第1张图片

首先用户C浏览并登录了受信任站点A;

登录信息验证通过以后,站点A会在返回给浏览器的信息中带上已登录的cookie,cookie信息会在浏览器端保存一定时间(根据服务端设置而定);

完成这一步以后,用户在没有登出(清除站点A的cookie)站点A的情况下,访问恶意站点B;

这时恶意站点 B的某个页面向站点A发起请求,而这个请求会带上浏览器端所保存的站点A的cookie;

站点A根据请求所带的cookie,判断此请求为用户C所发送的。

因此,站点A会跟据用户C的权限来处理恶意站点B所发起的请求,而这个请求可能以用户C的身份发送 邮件、短信、消息,以及进行转账支付等操作,这样恶意站点B就达到了伪造用户C请求站点 A的目的。

当用户完成以下两件事时,攻击者即可完成CSRF攻击

  1. 登录受信任站点 A,并在本地生成cookie;
  2. 在不登出站点A(清除站点A的cookie)的情况下,访问恶意站点B。

很多情况下所谓的恶意站点,很有可能是一个存在其他漏洞(如XSS)的受信任且被很多人访问的站点,这样,普通用户可能在不知不觉中便成为了受害者。

攻击的例子

CSRF攻击的主要目的是让用户在不知情的情况下攻击自己已登录的一个系统,类似于钓鱼。如用户当前已经登录了邮箱,或bbs,同时用户又在使用另外一个,已经被你控制的站点,我们姑且叫它钓鱼网站。这个网站上面可能因为某个图片吸引你,你去点击一下,此时可能就会触发一个get请求或者js的点击事件,构造一个bbs发帖的请求,去往你的bbs发帖,由于当前你的浏览器状态已经是登陆状态,所以session登陆cookie信息都会跟正常的请求一样,纯天然的利用当前的登陆状态,让用户在不知情的情况下,帮你发帖或干其他事情。

js获取Cookie的方式为:var strcookie = document.cookie

攻击的防御

  1. 尽量使用POST,限制GET

    GET接口太容易被拿来做CSRF攻击,看上面示例就知道,只要构造一个img标签,而img标签又是不能过滤的数据。接口最好限制为POST使用,GET则无效,降低攻击风险。
    当然POST并不是万无一失,攻击者只要构造一个form就可以,但需要在第三方页面做,这样就增加暴露的可能性。

  2. 将cookie设置为HttpOnly

    CRSF攻击很大程度上是利用了浏览器的cookie,为了防止站内的XSS漏洞盗取cookie,需要在cookie中设置“HttpOnly”属性,这样通过程序(如JavaScript脚本、Applet等)就无法读取到cookie信息,避免了攻击者伪造cookie的情况出现。
    在Java的Servlet的API中设置cookie为HttpOnly的代码如下:
    response.setHeader( "Set-Cookie", "cookiename=cookievalue;HttpOnly");

  3. 增加token

    CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于cookie中,因此攻击者可以在不知道用户验证信息的情况下直接利用用户的cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信总不存在于cookie之中。鉴于此,系统开发人员可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务端进行token校验,如果请求中没有token或者token内容不正确,则认为是CSRF攻击而拒绝该请求。
    假设请求通过POST方式提交,则可以在相应的表单中增加一个隐藏域:

    token的值通过服务端生成,表单提交后token的值通过POST请求与参数一同带到服务端,每次会话可以使用相同的token,会话过期,则token失效,攻击者因无法获取到token,也就无法伪造请求。在session中添加token的实现代码:

    HttpSession session = request.getSession();
    Object token = session.getAttribute("_token");
    if(token == null I I "".equals(token)) {
        session.setAttribute("_token", UUID.randomUUIDO .toString());
    }
    

    根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限的页面的请求都来自于同一个网站。比如某银行的转账是通过用户访问http://www.xxx.com/transfer.do页面完成的,用户必须先登录www.xxx.com,然后通过单击页面上的提交按钮来触发转账事件。当用户提交请求时,该转账请求的Referer值就会是
    提交按钮所在页面的URL(本例为www.xxx. com/transfer.do)。如果攻击者要对银行网站实施CSRF攻击,他只能在其他网站构造请求,当用户通过其他网站发送请求到银行时,该请求的Referer的值是其他网站的地址,而不是银行转账页面的地址。因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值即可,如果是以www.xx.om域名开头的地址,则说明该请求是来自银行网站自己的请求,是合法的;如果Referer是其他网站,就有可能是CSRF攻击,则拒绝该请求。
    取得HTTP请求Referer:
    String referer = request.getHeader("Referer");

    个人认为,此种方法有其局限性。

前后端分离模式下的Spring Boot框架防CRSF攻击

待完成

参考文献

[^1 ] CSRF实例

[^2 ] 怎么将cookie中httponly属性设置为true

[^3 ] js读取cookie 根据cookie名称获取值的方法

[^4 ] Token防止表单重复提交和CSRF攻击

你可能感兴趣的:(安全)