精华 CSRF攻击原理以及nodejs的实现和防御
发布于 12 年前 作者 jifeng 17082 次浏览 最后一次编辑是 8 年前

一、简介

CSRF (Cross-site Request Forgery),中文名称:跨站伪造。危害是攻击者可以盗用你的身份,以你的名义发送恶意请求。比如可以盗取你的账号,以你的身份发送邮件,购买商品等。

二、原理

具体的原理图如下 enter image description here

更加恐怖的是使用诸如img之类的标签,甚至不需要用户点击某个链接就可以发起攻击,比如B网站可以添加如下代码:

<img src='http://www.company.com/action?k1=v1&k2=v2' width=0 height=0 />

这里width=0 height=0 表示图片是不可见的。这个语句会导致游览器向另外的服务器发送一个请求。游览器不管该图片url实际是否指向一张图片,只要src字段中规定了url,就会按照地址触发这个请求。(游览器默认都是没有禁止下载图片,这是因为禁用图片后大多数web程序的可用性就会打折扣)。加载图片根本不考虑所涉及的图像所在位置(可以跨域)。如果A网站不小心提供了get接口就非常不幸得中招了

三、攻击

《浅谈CSRF攻击方式》一文中已经用实例讲解了一个php的实现和防御方法,我这里主要是讲nodejs的实现和防御。为了简单起见,假设我们有一个应用,它提供了两个接口“/get/checkvalue”和 “’/post/setvalue”,它们都接受一个参数“value”来改变系统的一个某个值。 当然前提是用户已经正常登陆了。具体逻辑是它有一个用户登陆的过程,登陆成功后会将用户信息存到cookie中,之后就根据cookie来判断是否能正常访问,当然cookie信息经过md5加密。(真实应用中千万不要这么做,md5加密并不是非常安全)。

具体的代码参见: https://github.com/jifeng/toycode/blob/master/csrf/app.js

那具体怎样进攻呢?

get攻击的页面很简单。

<img src='http://test3.data.taobao.com:5678/get/check?func=get&value=10'> 

post攻击的页面相对比较复杂

<html>
  <head>
    <title>post 测试页面</title>
    <script>
      function steal(){
         var mySubmit = document.getElementById('steal_form');
        mySubmit.submit();
      }
   </script>
 </head>
 <body onload='steal()'>
 <form id = "steal_form" method="POST"  action="http://test3.data.taobao.com:5678/post/check">
     <input type="hidden" name="func" value="post">
     <input type="hidden" name="value" value="1000">
   </form>
 </body>
</html> 

但这里强调一点:现在游览器(chrome,firfox)为了安全考虑,默认都做了一定的限制,form标签发送到其他网站的请求会被拦截,大家有兴趣模拟这种情况时需要注意这个问题。

四、防范

访问csrf的措施虽然很多,但归根到底就是一条:在客户端提交请求时增加伪造随机数。

nodejs中有些框架已经帮我们做了这件事,比如重用的connect

它具体的实现:http://www.senchalabs.org/connect/csrf.html

举例:https://github.com/senchalabs/connect/blob/master/examples/csrf.js

实现还是相对比较简单,有兴趣的同学可以再仔细看下。

14 回复

文中那篇《浅谈CSRF攻击方式》总结的还是挺到位的~
其实一些web安全问题,原理很简单,需要的只是程序猿或者网站所属公司的重视~

connect.csrf 对于同时打开多个不同的form页面时怎么处理token?

嗯,那篇文章的确写得很好,我也是受到那篇文章的启发才想写篇nodejs版

connect.csrf中token值是session中,所以每次用户会话,token都是同一个。具体看http://www.senchalabs.org/connect/csrf.html 其中

var token = req.session._csrf || (req.session._csrf = utils.uid(24));

好,收藏!

顶,安全问题,每个程序都要小心

@jifeng 这个token是明码保存在 <input type=hidden >中的,第三方可以读到, 会被用来伪造访问吗?

还有一个原则:涉及数据变更的请求不要用GET方法

@j4cnodejs token存在在服务器的session中,第三方一般是不可能直接获取到这token

嗯,用GET方法去更新数据本身就违反http规范。而且造成的后果很严重

补充: 防范里只提到了如何防范POST请求。 Referer检测也可以算做一条防范方法。

refer判断的确是中不错的方法,学习了

回到顶部