CSRF攻击与防御详解
字数 2953 2025-11-05 23:47:54

CSRF攻击与防御详解

一、CSRF攻击描述

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种恶意攻击方式。攻击者诱导用户在当前已登录的Web应用中执行非本意的操作。其核心原理是:利用用户在其他网站已经建立的登录状态(如Cookie),通过伪造请求,让用户在不知情的情况下执行攻击者预设的操作

举个例子:假设你登录了网上银行A,且登录状态Cookie有效。此时你访问了恶意网站B,B的页面中包含一个隐藏的图片标签,其src指向银行A的转账接口(如<img src="https://bank-a.com/transfer?to=attacker&amount=1000">)。浏览器在加载这个图片时,会自动携带你登录银行A的Cookie向该接口发起GET请求。银行A验证Cookie有效,便执行了转账操作。这就是一次典型的CSRF攻击。

二、攻击原理与必要条件

要成功实施CSRF攻击,必须同时满足以下三个关键条件:

  1. 目标网站存在可被利用的接口:应用存在一个能执行敏感操作(如修改密码、转账、发帖)的接口,该接口仅通过Cookie或“浏览器自动添加的凭证”进行身份验证。
  2. 用户已登录目标网站:用户的浏览器中保存着目标网站的有效登录会话(Session Cookie),且该Cookie尚未过期。
  3. 用户被诱骗访问恶意页面:攻击者诱导用户访问一个精心构造的页面(如钓鱼邮件、恶意网站),该页面会自动向目标网站接口发起请求。

三、攻击的常见实现方式

攻击者伪造请求的方式多种多样,主要分为三类:

  1. GET请求攻击

    • 方式:将恶意请求参数直接放在URL中,通过<img><script><link><iframe>等标签的srchref属性触发。浏览器会自动发起GET请求。
    • 示例
      <!-- 用户访问包含此代码的页面,会悄悄发起转账 -->
      <img src="https://bank.com/transfer?to=hacker&amount=100000" width="0" height="0">
      
  2. POST请求攻击

    • 方式:在恶意页面中构建一个隐藏的<form>,并自动提交(通过JavaScript的submit()方法)。
    • 示例
      <body onload="document.forms[0].submit()">
        <form action="https://bank.com/change_password" method="POST">
          <input type="hidden" name="new_password" value="hacker_controlled" />
        </form>
      </body>
      
  3. 其他HTTP方法攻击

    • 对于PUT、DELETE等请求,也可以通过构造XMLHttpRequest或Fetch请求来实现,但通常会受到浏览器的同源策略(CORS)限制,具体取决于目标服务器的CORS配置。

四、防御策略详解

防御CSRF的核心思想是增加攻击者无法预测、无法伪造的校验信息。以下是逐层深入的防御方案:

第一层:同源检测(基础防御)

利用HTTP请求头中的OriginReferer字段,它们会告知服务器请求的来源地址。

  • Origin:指明请求来自哪个站点(协议+域名+端口)。对于同源请求或一些特殊情况(如IE11),可能不会发送。
  • Referer:包含完整的请求来源URL。
  • 防御步骤
    1. 服务器在处理敏感请求(非GET)时,检查OriginReferer头。
    2. 判断其值是否与服务器的域名一致。
    3. 如果不一致,则拒绝请求。
  • 优点:简单易实现。
  • 缺点
    • 隐私或安全策略可能导致浏览器不发送这些头。
    • 低版本浏览器可能存在漏洞。
    • 不能作为唯一防御手段,应与其他方法结合。

第二层:CSRF Token(主流且最有效的方案)

这是目前最可靠、最广泛的防御机制。

  • 原理:在用户会话(Session)中生成一个随机、不可预测的令牌(Token)。在需要保护的请求(如表单、AJAX请求)中携带此Token。服务器在处理请求时,校验Token的有效性。

  • 详细流程

    1. 生成Token:用户访问应用时,服务器为其Session生成一个随机的CSRF Token。
    2. 传递Token:服务器将此Token嵌入到返回给用户的表单中(作为隐藏字段),或通过设置到全局变量(如meta标签)供前端JavaScript获取。
      <!-- 表单示例 -->
      <form action="/transfer" method="POST">
        <input type="hidden" name="csrf_token" value="randomly_generated_string">
        <!-- ... 其他表单字段 -->
      </form>
      
    3. 携带Token:用户提交表单或发起AJAX请求时,前端代码必须将此Token包含在请求中(表单字段或请求头,如X-CSRF-TOKEN)。
    4. 服务器验证:服务器收到请求后,从Session中取出之前存储的Token,并与请求中携带的Token进行比对。
      • 如果一致,请求合法,执行操作。
      • 如果不一致、缺失或过期,请求被认定为伪造,立即拒绝并返回错误。
  • 为什么能防御CSRF?

    • 同源策略保护:恶意网站B无法通过JavaScript读取到用户在其他网站A的CSRF Token值(因为受同源策略限制)。
    • 不可预测性:攻击者无法猜出或伪造出正确的Token值。

第三层:双重Cookie验证(替代方案)

此方案将Token放在Cookie中,但要求前端脚本将其读出并作为请求参数或头传递。

  • 流程
    1. 用户访问时,服务器在响应中设置一个Cookie(如csrf_token=random_string)。
    2. 前端JavaScript读取此Cookie的值。
    3. 发起请求时,将此值作为参数(如x-csrf-token)或自定义请求头(如X-CSRF-TOKEN)一起发送。
    4. 服务器收到请求后,比对Cookie中的Token值和参数/头中的Token值是否一致。
  • 优点:实现相对简单,无需在服务器端为每个Session存储Token(但Cookie本身是Session的一部分)。
  • 缺点
    • 如果网站存在XSS漏洞,攻击者可以读取Cookie,此方案即告失效。
    • 需要确保子域名安全,否则子域名间的Cookie可能被篡改。

第四层:利用SameSite Cookie属性(现代浏览器强力补充)

这是浏览器提供的一种从源头遏制CSRF的机制。

  • 原理:通过设置Cookie的SameSite属性,控制Cookie在跨站请求时是否被发送。
  • 三种模式
    • Strict:最严格。Cookie仅在同站请求(即当前页面URL与请求目标URL的eTLD+1相同)时发送。完全阻止CSRF,但可能影响用户体验(如从外部链接点进来,登录状态会丢失)。
    • Lax:宽松模式。在安全跨站请求(如GET请求、页面跳转)中发送Cookie,但在不安全的跨站POST请求中不发送。这是目前很多站点的默认推荐设置,能在安全性和可用性间取得平衡。
    • None:Cookie在所有上下文中发送,但必须同时设置Secure属性(即仅通过HTTPS传输)。
  • 设置示例(在HTTP响应头中):
    Set-Cookie: sessionid=abc123; SameSite=Lax; Secure
    

总结与最佳实践

  1. 首选方案CSRF Token是防御CSRF攻击最坚固的基石。确保Token随机、一次性(或短期有效),并与用户Session绑定。
  2. 强力补充:为所有认证相关的Cookie设置SameSite=LaxStrict属性。这能从根本上阻止大多数类型的CSRF攻击。
  3. 组合防御:对于关键操作,可以结合使用Token和SameSite属性。同时,对敏感请求进行同源检测作为额外保障。
  4. 安全意识:确保应用没有XSS漏洞,因为XSS可以绕过大多数CSRF防御(如窃取Token)。
  5. 避免使用GET进行状态变更:严格遵守HTTP语义,GET请求只用于获取数据,不应用于执行任何有副作用的操作。这能防止简单的GET型CSRF攻击。
CSRF攻击与防御详解 一、CSRF攻击描述 CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种恶意攻击方式。攻击者诱导用户在当前已登录的Web应用中执行非本意的操作。其核心原理是: 利用用户在其他网站已经建立的登录状态(如Cookie),通过伪造请求,让用户在不知情的情况下执行攻击者预设的操作 。 举个例子:假设你登录了网上银行A,且登录状态Cookie有效。此时你访问了恶意网站B,B的页面中包含一个隐藏的图片标签,其 src 指向银行A的转账接口(如 <img src="https://bank-a.com/transfer?to=attacker&amount=1000"> )。浏览器在加载这个图片时,会自动携带你登录银行A的Cookie向该接口发起GET请求。银行A验证Cookie有效,便执行了转账操作。这就是一次典型的CSRF攻击。 二、攻击原理与必要条件 要成功实施CSRF攻击,必须同时满足以下三个关键条件: 目标网站存在可被利用的接口 :应用存在一个能执行敏感操作(如修改密码、转账、发帖)的接口,该接口仅通过Cookie或“浏览器自动添加的凭证”进行身份验证。 用户已登录目标网站 :用户的浏览器中保存着目标网站的有效登录会话(Session Cookie),且该Cookie尚未过期。 用户被诱骗访问恶意页面 :攻击者诱导用户访问一个精心构造的页面(如钓鱼邮件、恶意网站),该页面会自动向目标网站接口发起请求。 三、攻击的常见实现方式 攻击者伪造请求的方式多种多样,主要分为三类: GET请求攻击 方式 :将恶意请求参数直接放在URL中,通过 <img> 、 <script> 、 <link> 、 <iframe> 等标签的 src 或 href 属性触发。浏览器会自动发起GET请求。 示例 : POST请求攻击 方式 :在恶意页面中构建一个隐藏的 <form> ,并自动提交(通过JavaScript的 submit() 方法)。 示例 : 其他HTTP方法攻击 对于PUT、DELETE等请求,也可以通过构造XMLHttpRequest或Fetch请求来实现,但通常会受到浏览器的同源策略(CORS)限制,具体取决于目标服务器的CORS配置。 四、防御策略详解 防御CSRF的核心思想是 增加攻击者无法预测、无法伪造的校验信息 。以下是逐层深入的防御方案: 第一层:同源检测(基础防御) 利用HTTP请求头中的 Origin 和 Referer 字段,它们会告知服务器请求的来源地址。 Origin 头 :指明请求来自哪个站点(协议+域名+端口)。对于同源请求或一些特殊情况(如IE11),可能不会发送。 Referer 头 :包含完整的请求来源URL。 防御步骤 : 服务器在处理敏感请求(非GET)时,检查 Origin 或 Referer 头。 判断其值是否与服务器的域名一致。 如果不一致,则拒绝请求。 优点 :简单易实现。 缺点 : 隐私或安全策略可能导致浏览器不发送这些头。 低版本浏览器可能存在漏洞。 不能作为唯一防御手段 ,应与其他方法结合。 第二层:CSRF Token(主流且最有效的方案) 这是目前最可靠、最广泛的防御机制。 原理 :在用户会话(Session)中生成一个随机、不可预测的令牌(Token)。在需要保护的请求(如表单、AJAX请求)中携带此Token。服务器在处理请求时,校验Token的有效性。 详细流程 : 生成Token :用户访问应用时,服务器为其Session生成一个随机的CSRF Token。 传递Token :服务器将此Token嵌入到返回给用户的表单中(作为隐藏字段),或通过设置到全局变量(如 meta 标签)供前端JavaScript获取。 携带Token :用户提交表单或发起AJAX请求时,前端代码必须将此Token包含在请求中(表单字段或请求头,如 X-CSRF-TOKEN )。 服务器验证 :服务器收到请求后,从Session中取出之前存储的Token,并与请求中携带的Token进行比对。 如果一致,请求合法,执行操作。 如果不一致、缺失或过期,请求被认定为伪造,立即拒绝并返回错误。 为什么能防御CSRF? 同源策略保护 :恶意网站B无法通过JavaScript读取到用户在其他网站A的CSRF Token值(因为受同源策略限制)。 不可预测性 :攻击者无法猜出或伪造出正确的Token值。 第三层:双重Cookie验证(替代方案) 此方案将Token放在Cookie中,但要求前端脚本将其读出并作为请求参数或头传递。 流程 : 用户访问时,服务器在响应中设置一个Cookie(如 csrf_token=random_string )。 前端JavaScript读取此Cookie的值。 发起请求时,将此值作为参数(如 x-csrf-token )或自定义请求头(如 X-CSRF-TOKEN )一起发送。 服务器收到请求后,比对Cookie中的Token值和参数/头中的Token值是否一致。 优点 :实现相对简单,无需在服务器端为每个Session存储Token(但Cookie本身是Session的一部分)。 缺点 : 如果网站存在XSS漏洞,攻击者可以读取Cookie,此方案即告失效。 需要确保子域名安全,否则子域名间的Cookie可能被篡改。 第四层:利用SameSite Cookie属性(现代浏览器强力补充) 这是浏览器提供的一种从源头遏制CSRF的机制。 原理 :通过设置Cookie的 SameSite 属性,控制Cookie在跨站请求时是否被发送。 三种模式 : Strict :最严格。Cookie仅在同站请求(即当前页面URL与请求目标URL的eTLD+1相同)时发送。完全阻止CSRF,但可能影响用户体验(如从外部链接点进来,登录状态会丢失)。 Lax :宽松模式。在安全跨站请求(如GET请求、页面跳转)中发送Cookie,但在不安全的跨站POST请求中不发送。这是目前很多站点的默认推荐设置,能在安全性和可用性间取得平衡。 None :Cookie在所有上下文中发送,但必须同时设置 Secure 属性(即仅通过HTTPS传输)。 设置示例 (在HTTP响应头中): 总结与最佳实践 首选方案 : CSRF Token 是防御CSRF攻击最坚固的基石。确保Token随机、一次性(或短期有效),并与用户Session绑定。 强力补充 :为所有认证相关的Cookie设置 SameSite=Lax 或 Strict 属性。这能从根本上阻止大多数类型的CSRF攻击。 组合防御 :对于关键操作,可以结合使用Token和 SameSite 属性。同时,对敏感请求进行同源检测作为额外保障。 安全意识 :确保应用没有XSS漏洞,因为XSS可以绕过大多数CSRF防御(如窃取Token)。 避免使用GET进行状态变更 :严格遵守HTTP语义,GET请求只用于获取数据,不应用于执行任何有副作用的操作。这能防止简单的GET型CSRF攻击。