必掌握的安全隐患--之CSRF攻击

Posted nginx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了必掌握的安全隐患--之CSRF攻击相关的知识,希望对你有一定的参考价值。

CSRF是什么?


(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性


CSRF可以做什么?


你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。


它这么厉害,那它的原理是什么?


通过下图来简述原理

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  • 登录受信任网站A,并在本地生成Cookie。

  • 在不登出A的情况下,访问危险网站B。
    看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:

1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)
3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。


几种常见的攻击类型


GET类型的CSRF

这种类型的CSRF一般是由于程序员安全意识不强造成的。GET类型的CSRF利用非常简单,只需要一个HTTP请求,所以,一般会这样利用:


<img src=http://wooyun.org/csrf?xx=11 /> 



POST类型的CSRF

这种类型的CSRF危害没有GET型的大,利用起来通常使用的是一个自动提交的表单,如:


<form action=http://wooyun.org/csrf.php method=POST>
<input type="text" name="xx" value="11" />
</form>
<script> document.forms[0].submit(); </script>


访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。


其他其他猥琐流CSRF

过基础认证的CSRF(常用于路由器):

POC:


<img src=http://admin:admin@192.168.1.1 /> 


加载该图片后,路由器会给用户一个合法的SESSION,就可以进行下一步操作了。


防御CSRF的策略


道高一尺,魔高一丈。



验证 HTTP Referer 字段



这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心 CSRF 的漏洞,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以。


即便是使用最新的浏览器,黑客无法篡改 Referer 值,这种方法仍然有问题。因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心 Referer 值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。当他们正常访问银行网站时,网站会因为请求没有 Referer 值而认为是 CSRF 攻击,拒绝合法用户的访问。


在请求地址中添加 token 并验证


CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。


这种方法要比检查 Referer 要安全一些,token 可以在用户登陆后产生并放于 session 之中,然后在每次请求时把 token 从 session 中拿出,与请求中的 token 进行比对,但这种方法的难点在于如何把 token 以参数的形式加入请求。



在 HTTP 头中自定义属性并验证



防御实例


Sailajs框架中的JavaScript 代码示例


下面将以 javascript 为例,对上述三种方法分别用代码进行示例。


1.验证 Referer

// 从 HTTP 头中取得 Referer 值
var referer=req.headers.Referer;
// 判断 Referer 是否以 test.example 开头
if((referer!=null) && (_.startsWith(referer, “test.example ”)){
   // 验证通过
}else{
   // 验证失败,返回错误
}


2.验证请求中的 token

var session = req.session;
// 从 session 中得到 csrftoken 属性
var  token = session.csrftoken;
if(token == null){
   // 产生新的 token 放入 session 中
   token = generateToken();
   token.csrftoken = token ;
  return ....
} else{
   // 从 HTTP 头中取得 csrftoken
   var  token = req.headers.csrftoken;
   // 从请求参数中取得 csrftoken
   var  xhrToken = req.param('csrftoken');
   if(token != null && xhrToken != null && token.equals(xhrToken)){
      return ...
   }else{
       return ...  // ERROR
   }
}


  1. HTTP 头中自定义属性(网上例子)

var plainXhr = dojo.xhr; 
// 重写 dojo.xhr 方法
dojo.xhr = function(method,args,hasBody) {
   // 确保 header 对象存在
   args.headers = args.header || {};
   tokenValue = '<%=request.getSession(false).getAttribute("csrftoken")%>';
   var token = dojo.getObject("tokenValue");
   // 把 csrftoken 属性放到头中
   args.headers["csrftoken"] = (token) ? token : "  ";
   return plainXhr(method,args,hasBody);
};


总结


CSRF 是一种危害非常大的攻击,又很难以防范。目前几种防御策略虽然可以很大程度上抵御 CSRF 的攻击,但并没有一种完美的解决方案。一些新的方案正在研究之中,比如对于每次请求都使用不同的动态口令,把 Referer 和 token 方案结合起来,甚至尝试修改 HTTP 规范,但是这些新的方案尚不成熟,要正式投入使用并被业界广为接受还需时日。在这之前,我们只有充分重视 CSRF,根据系统的实际情况选择最合适的策略,这样才能把 CSRF 的危害降到最低。


文章推荐

1


2


3


4


5





以上是关于必掌握的安全隐患--之CSRF攻击的主要内容,如果未能解决你的问题,请参考以下文章

CSRF 攻击的应对之道

web安全之CSRF(跨站域请求伪造)攻击详解应对和测试

CSRF攻防之道

如何解决CSRF 攻击

保护ASP.NET 应用免受 CSRF 攻击

剖析使用CSRF攻击实现银行转账原理