web安全漏洞之CSRF

一.CSRF(跨站请求攻击)攻击的原理:

1.攻击原理:

  1. 网站使用cookie来存放用户的登陆凭证
  2. cookie会在同源的http请求中自动携带

2.基本攻击过程:

  1. 用户登陆了受信任网站A,并在本地生成网站A的cookie
  2. 不登出网站A(A网站的cookie还有效),访问了危险网站B
  3. 危险网站B里面隐藏了一些访问A的接口,用户在访问B网站的时候,就会不自觉的去调用访问A网站的接口,这时候由于A网站的cookie还有效,因此危险网站B里面隐藏的对A的接口就能访问成功

二.CSRF攻击示例:

1.示例:

  • 例如,aaa.com这个网页都是经过session_id来记录用户的登陆状态的
  • aaa.com页面上有一个对做品点赞的功能,点赞提交地址为aaa.com/api.like?id=777
  • 小明已经登陆了ww.aaa.com,天然aaa.com这个网站就会将小明的登陆状态session_id存在cookie
  • 黑客本身建立了另一个网站bbb.com,并在页面中放了这样一个元素<img src="aaa.com/api.like?id=888">,这样的话,一旦用户进入这个bbb.com页面,就会请求aaa.com这个网站的点赞接口aaa.com/api.like?id=888,并且点赞的用户对象是888
  • 小明登陆了aaa.com,且代表身份信息的cookie尚未失效
  • 最后由于小明的登陆信息还没有过时,访问时就会带上aaa.com的cookie(该过程详见 这里),那就等于给id为888这个做品点赞了

image

2.常见的CSRF攻击手段总结:

  1. 欺骗受害用户完成该用户权限许可的任意操做,例如:
    • 获取用户的隐私数据——诱骗用户调用获取隐私数据的接口
    • 更改用户帐号的内容——诱骗用户调用修改帐号信息的接口
    • 购物消费——诱骗用户调用消费接口
    • ...
  2. 配合其余漏洞攻击
  3. CSRF蠕虫——即产生蠕虫效果,使CSRF攻击一传十,十传百
    • 示例:有一个聊天网站A,它的 ++获取好友列表接口++ 和 ++私信好友接口++ 都存在CSRF漏洞,攻击者能够将其组合成一个CSRF蠕虫:
      • 用户已经登陆了网站A,且不登出
      • 黑客发布一个危险网站B,用户访问时,就会被诱骗访问获取好友列表接口,获取好友的信息
      • 而后再利用私信好友的漏洞,诱骗用户给每一个好友发送指向网站B的信息
      • 只要有好友查看了这条私信信息里面的连接,CSRF蠕虫就会不断的传播下去

三.CSRF的接口攻击类型:

CSRF不只针对GET请求,其余的类型的请求均可被利用来攻击php

1.GET类型(最简单的)

  1. 方式1:借助一些自动发起请求的元素
    • 例如,在访问含有这个img的页面后,成功向http://wooyun.org/csrf?xx=11 发出了一次HTTP请求
// 只要设置这个图片的宽高为0,用户是根本感受不到这个`<img>`元素存在
<img src=http://wooyun.org/csrf?xx=11 /> 
复制代码
  1. 方式2:页面里面放入一个自动提交的表单,模拟一次GET请求html

  2. 方式3:页面内部自动发起一个get方法的ajax请求前端

2.POST类型

  1. 方式1:页面里面放入一个自动提交的表单,模拟一次POST请求
<form action=http://wooyun.org/csrf.php method=POST>
<input type="text" name="xx" value="11" />
</form>
<script> document.forms[0].submit(); </script>
复制代码
  1. 方式2:页面内部自动发起一个post方法的ajax请求
  2. 方式3:页面以GET请求发起,后台接受到后再以POST方式转发

四.规避攻击的方法:

1.后端判断referer是否合法(不推荐)

  • Referer记录了HTTP请求的来源地址
    • 通常状况下,受一个页面安全限制的请求都是来源于这个网站
    • 经过HTTP的referer可知道,用户是经过哪一个网站发送这个请求的。
// koa服务器检查Referer示例:
app.use(async (ctx, next) => {
    let referer = ctx.headers.Referer;
    // 验证Referer是不是以 test.example 开头的
    if((referer != null ) && (_.startsWith(referer, "test.example")) {
        // 验证经过
        await next();
    } else {
        验证失败,返回错误
        ctx.status = 401;
        return ctx.body = {
            err: '危险的请求,拒绝访问'
        }
    }
}) 
复制代码
  • 注意: Referer的判断并非好方法,有不少缺陷,具体可见 这里
    1. 某些浏览器,例如IE6FF2都是能够本身设置Referer值的
    2. 由于Referer会记录用户的访问记录,侵犯隐私,所以在最新的浏览器中,用户能够本身设置发送请求时再也不提供Referer,这种在请求时就会被误看成CSRF攻击
    3. 判断referer是否为某域名,能够本身来伪造
      • 例如:判断Referer开头是否以 126.com 以及 126 子域名,而不验证根域名为126.com,这里就能够伪造出 x.126.com.xxx.com 的域名
    4. ...

2.请求中添加上token并验证,即校验信息不经过cookie来实现

  1. 该作法的缘由
    • 要明白cookie得到携带的区别:
      • 得到cookie: 即经过js获取cookie中的参数值,有同源策略的限制
      • 携带cookie: http请求时自动携带上cookie,会自动带上该同源域下的全部cookie
    • token是csrf.com页面渲染时一块儿带过来的,这样的话,若是不在csrf.com页面发起这个点赞请求,不一样域的网站是拿不到token的
    • 而CSRF只能经过自动携带cookie去发起攻击,,所以此方式可拦截
  2. 两种具体作法
    1. 前端记录token,在请求参数中添加token,后台判断:
    // 前端
        //登陆成功后,将token保存在本地(能够是cookie方式,也能够是 localStorage 方式)
        // 而后每次请求时添加一个 token 参数
    
    // 后端,每一个请求过来都验证token是否有效:
    app.use( async (ctx, next) => {
        var token = req.session.token;
        var csrfToken = req.param.csrftoken;
        if(token != null && xhrToken != null && token.equals(xhrToken)) {
            // success
            await next();
        } else {
            // error
            return error
        }
    })
    复制代码
    1. 前端记录token,在请求头中添加自定义头,存放token,后台判断:
    // expressJwt是express框架中可用的JWT校验插件
    var expressJwt = require('express-jwt');
    var validateJwt = expressJwt({ secret: config.secrets.session });
    app.use( async (ctx, next) => {
        // 也一样容许校验 token 在请求参数中的
        if(req.query && req.query.hasOwnProperty('access_token')) {
            req.headers.authorization = 'Bearer' + req.query.access_token;
        }
        // 下面会校验请求头中的 authorization 头
        validateJwt(ctx, next);
    })
    复制代码

五.注意和总结:

  1. CSRF攻击针对的是以cookie机制来验证登陆权限的接口
  2. CSRF攻击不只能够攻击get类型的接口,也能够攻击其余方法类型的接口
  3. CSRF攻击的对象,无论有没有开放同源接口访问限制,由于能够经过表单的方式发起请求,无视跨域限制
  4. 解决CSRF攻击最有效的方法就是在请求中携带token到后台去验证
    • 能够在请求参数中携带
    • 能够在请求头中携带
相关文章
相关标签/搜索