• CSRF 漏洞学习笔记


    什么是 CSRF 漏洞

    CSRF(Cross Site Request Forgery,跨站请求伪造,也叫 XSRF)漏洞是由于未校验请求来源,导致攻击者可在第三方站点发起 HTTP 请求,并以受害者的目标网站登录态(cookie、session 等)请求,从而执行一些敏感的业务功能操作,比如更改密码、修改个人资料、关注好友。
    在这里插入图片描述

    从以上可以得知,漏洞比较依赖业务功能。有时虽然存在 CSRF 但并没有实际危害,也不能算是真正意义上的 CSRF 漏洞。比如常规的登录账号功能,如果你不知道密码就无法登录,而如果知道了,那还需要构造 CSRF 请求吗?如果是为了实现多次登录失败,令目标账号暂时无法登录,那么也不需要用 CSRF。如果是一些发消息、发微博的功能,那同样可以产生蠕虫效果,比如微博就曾发生过好多次此类 CSRF 蠕虫漏洞。

    CSRF 分类

    从漏洞利用角度来分类的话,CSRF 可以分为 CSRF 读与 CSRF 写。

    • CSRF 读:通过伪造请求来获取返回的敏感信息,比如用户资料;常见的就是 JSON 劫持,以及利用 Flash API加载页面获取敏感信息。
    • CSRF 写:通过伪造请求去修改网站数据,比如修改密码、发表文章、发送消息等操作。

    CSRF 的攻击手法

    以 DVWA 中的 CSRF 题目(Security Level 设置为 Low)为例
    在这里插入图片描述
    输入密码提交的同时抓包。此处直接用 Chrome 的 Network 功能,抓包后发现只是个 GET 请求,那利用起来就简单了:直接构造以下链接发给受害者,受害者点击后就会被修改密码为你设置的密码。如下所示:
    http://127.0.0.1/vulnerabilities/csrf/?password_new={你设置的密码}&password_conf={你设置的密码}&Change=Change

    像这种 GET 型的 CSRF 漏洞利用就是仅需要修改下原 GET 的参数值,构造个链接发给对方就可以了;甚至直接使用图片链接嵌入到受害者可能访问的页面(博客、论坛、邮件等等),也可以实现漏洞的利用,这种利用方式更加隐蔽。
    如果是 POST 请求,就需要编写利用代码,用 JS 脚本去实现自动提交表单,然后把它放在自己控制的服务器上。假设存放地址为 http://hacker.com/exploit.html ,再生成短网址 http://dwz.date/d74a 发给受害者。
    在这里插入图片描述
    exploit.html 利用代码如下:

    <html>
    <form name = "test" action = "http://127.0.0.1/vulnerabilities/csrf" method = "post" >
    <input type = "hidden" value="hacker" name="password_new" >
    <input type = "hidden" value="hacker" name="password_conf" >
    <input type = "hidden" value="Change" name="Change" >
    </form>
    <script>document.test.submit();</script>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里是就模拟原网站的表单提交内容设置的,每个 input 都添加 type=“hidden” 的属性是为了不在网页中显示,最后再利用 document.test.submit() 去自动提交表单,其中 “test” 是指 form 名单。
    如果受害者访问上述包含 exploit.html 的 http://dwz.date/d74a ,就会发起以下请求:
    在这里插入图片描述

    上述的利用方式主要介绍的是 POST 类型的利用手法。

    JSON 劫持攻击

    JSON(JavaScript Object Notation,JavaScript 对象符号)是一种可以序列化任意数据,并能被 JavaScript 注释器直接处理的简单数据交换格式。我们来看一段 JSON 格式的包含用户信息的数据:

    { 
      "people":[ 
        {
          "name": "Brett",
          "email":"Brett@qq.com"
        },
        {
          "name":"Jason",
          "Jason@qqx.com"
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    JSON 劫持是一种特殊的 CSRF 攻击方式,本质上也是未对请求来源做有效校验导致的,它主要是用来窃取服务器返回的敏感信息。
    实现 JSON 劫持主要有两种攻击方式:覆写数据构造器和执行回调函数。

    覆写数据构造器

    若服务端返回的 JSON 数据中包含一个序列化数组,那攻击者就可以重定义数组构造器,以实现 JSON 数据的访问。比如 2006 年的 Gmail 就曾出现过 JSON 劫持联系人列表的漏洞,漏洞 CGI 位于:
    http://mail.google.com/mail/?url_scrubbed

    它会返回联系人列表的 JSON 数据。
    [[“ct”,“Your Name”,“foo@gmail.com”], [“ct”,“Another Name”,“bar@gmail.com”] ]

    因此,可通过覆盖数组构造器来读取 JSON 数据。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    从以上代码中我们可以总结整个攻击流程:

     - 通过<script>加载目标 JSON 对象到页面中;
     - 覆写 Array 对象,并设置数组元素的 setter 为 getNext 函数,有时也可以使用Object.prototype.__defineSetter__来覆盖 setter;
     - getNext 函数读取包含联系人信息的 JSON 信息。
    
    • 1
    • 2
    • 3
    执行回调函数

    不同域名之间传递数据时,无法通过 JavaScript 直接跨域访问,因此需要在访问脚本的请求中指定一个回调函数,用于处理 JSON 数据。正因如此,攻击者也可以利用它来劫持其他域返回的数据。这种攻击方式是当前 JSON 劫持中最为常见的方式。
    以前的 QQ 网购就曾出现过这种 JSON 劫持漏洞,其利用代码如下:

    <html>
    <body>
    <script>
      function any(obj){
        alert(obj);	
      }
    </script>
    <script src='http://act.buy.qq.com/w/newbie/queryisnew?callback=any' ></script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    通过 callback 参数指定返回数据的处理函数 any,在 any 函数中,你可以根据 JSON 数据内容执行特定的处理,获取你想要的数据然后回传到自己控制的服务器上。
    CSRF 检测方法:
    通过前面对 CSRF 原理的讲解,测试思路就很容易了:

    1. 抓包记录正常的 HTTP 请求;
    2. 分析 HTTP 请求参数是否可预测,以及相应的用途;
    3. 去掉或更改 referer 为第三方站点,然后重放请求;
    4. 判断是否达到与正常请求的同等效果,若是则可能存在 CSRF 漏洞,反之则不存在。

    自动化的测试思路也是一样的实现方法,只不过很多时候不知道请求参数的实际用途,比较难评估其危害和价值。正如前面所说的,CSRF 的危害取决于参数用途,这也导致很多时候需要人工验证,不然很容易误报。我个人认为,目前没有特别好的自动化 CSRF 检测工具,大多是一些半自动的辅助类工具,比如 BurpSuite 上的 CSRF PoC 生成功能。

    防御 CSRF

    防御 CSRF 的关键思路就是令请求参数不可预测,所以常用的方法就是在敏感操作请求上使用 POST 代替 GET,然后添加验证码或 Token 进行验证。
    这里不推荐 referer(即请求头中的来源地址)限制方法,因为通过 javascript:// 伪协议就能以空 referer 的形式发起请求,很容易绕过限制。如果你直接禁止空 referer,一些移动 App 上的请求又可能无法完成,因为移动 App 上的 http/https 请求经常是空 referer。

    验证码

    在一些重要的敏感操作上设置验证码(短信、图片等等),比如更改密码(此场景下也可要求输入原密码,这也是不可预测值)、修改个人资料等操作时。

    Token 验证

    对于 CSRF 的防御,Token 验证无疑是最常用的方法,它对用户是无感知的,体验上比验证码好太多了。
    在提交的表单中,添加一个隐藏的 Token,其值必须是保证不可预测的随机数,否则没有防御效果。下面是服务器生成并返回给当前用户的:

    提交表单后,会连同此 Token 一并提交,由服务器再做比对校验。
    生成 Csrf Token 的算法,常常会取登录后 cookie 中的某值作为输入,然后采用一些加密/哈希算法生成,这也是为了方便后台校验和区分用户。
    除了 Cookie Token,还可以使用伪随机值的 Session Token,即服务端生成一个伪随机数,存储到 $_SESSION 中,然后返回给用户的页面中隐藏此 Token;等用户提交后,再拿它与存储在 $_SESSION 的 Token 值比较。这是当前比较常用的 Token 生成与校验方式。

    总结下,先由服务端生成随机数作为 Token,然后存储到 Session 中,不一定都非要存储到 Cookie 中,然后在返回给用户的表单中插入隐藏的 Token,用户提交后,由服务器来比对提交的 Token 与 Session 中的 Token 是否一致,以此判断请求是否合法。

  • 相关阅读:
    美国亚马逊遥控无人机出口UL961的测试报告
    JavaWeb 项目 --- 博客系统(前后分离)
    读书笔记:《心若菩提》 曹德旺
    EL表达式与JSTL标签
    QT 绘制波形图、频谱图、瀑布图、星座图、眼图、语图
    Node.js | express 中间件详解(应用级 | 路由级 | 内置(托管静态资源) | 第三方)
    好久没写博客,成懒狗了
    【毕业设计】58-基于51单片机的智能语音密码锁设计(原理工程+PCB工程+仿真工程+源代码+答辩论文+实物图)
    Linux系统编程——总结初识Linux(常用命令、特点、常见操作系统)
    uniapp——组件多颜色模块展示、气泡框
  • 原文地址:https://blog.csdn.net/qq_32812063/article/details/128011268