详细聊聊CSRF攻击,以及Django项目应该如何防范

深度聊聊CSRF攻击


前言

公司有项目需要入国网供电公司的内网,需要经过电科院的检测。虽然项目后端是Java,暂时不太熟,但是想详细聊聊CSRF攻击,为什么攻击者能拿到被攻击网站的cookie,以及Django项目该如何防范

仅是抛砖引玉,希望能引发大家的思考

1. csrf攻击的定义

CSRF 攻击指的是跨站请求伪造,攻击者诱导用户进入一个第三方网站,然后该网站向被攻击网站发送跨站请求。如果用户在被攻击网站中保存了登录状态,那么攻击者就可以利用这个登录状态,绕过后台的用户验证,冒充用户向服务器执行一些操作。

CSRF 攻击的本质是利用 cookie 会在同源请求中携带发送给服务器的特点,以此来实现用户的冒充。

2. 为什么攻击者的网站能拿到被攻击网站的cookie

  • 原因一: cookie 会在请求时自动被浏览器携带,其他网站发起请求时仍然可以自动带上cookie

  • 原因二:cookie不能跨域访问(除非是在cookie的domain允许的子域),但是可以跨站点共享。此时的被自动携带的 cookie 被称为 第三方cookie

a. 什么是跨域和跨站

详细可参考讲清楚同源、跨源、同站、跨站

站(site) 部分域名+顶级域名

在同一浏览器,当前打开的多个Tab页网站,无论是否为同一站点,cookie都是共享可见的。这个共享不是说每个网站的脚本可以访问别的网站的cookie,而是说,你向同一服务器发送请求时,会带上浏览器保存的对于那个服务器的所有cookie,而不管你从哪个网站发起的请求

参考它 juejin.cn/post/695841...

什么是cookie

MDN给出的定义是服务器发送到用户浏览器并保存在本地的一小块数据。浏览器会存储 cookie 并在下次向同一服务器再发起请求时携带并发送到服务器上

服务器收到 HTTP 请求后,服务器可以在响应标头里面添加一个或多个 Set-Cookie 选项。浏览器收到响应后通常会保存下 Cookie,并将其放在 HTTP Cookie 标头内,向同一服务器发出请求时一起发送。你可以指定一个过期日期或者时间段之后,不能发送 cookie。你也可以对指定的域和路径设置额外的限制,以限制 cookie 发送的位置。关于下面提到的头部属性的详细信息,请参考 Set-Cookie 文章

这是因为HTTP协议是无状态的,也就是说,服务器无法知道请求是由哪个客户端发出的。为了解决这个问题,引入了cookie机制。当客户端第一次向服务器发送请求时,服务器会在响应头中添加一个Set-Cookie字段,该字段包含了一个唯一的标识符(cookie),并将该标识符存储在客户端的浏览器中。当客户端再次向服务器发送请求时,浏览器会自动将该标识符携带到服务器端,从而实现了状态的保持。

从定义里可知道 cookie 会在请求时自动被浏览器携带

3.典型场景

  1. 钓鱼网站:攻击者创建一个看似合法的网站,引诱用户访问。在该网站上,攻击者可能包含了针对另一个网站的恶意CSRF请求。当用户在不知情的情况下登录到目标网站时,他们的认证信息将用于执行恶意请求。
  2. 恶意电子邮件或消息:攻击者可以发送包含恶意链接或图像的电子邮件或社交媒体消息。当用户查看这些电子邮件或消息时,可能会在后台执行CSRF攻击。

4. django前后端分离项目,如何防范 CSRF攻击

最常用的方法:使用csrf token。

设置CSRFtoken

官网如何做的 docs.djangoproject.com/zh-hans/4.1...

  • a. 前端设置 前端获取cookie中的csrftoken,将其加入到请求头,字段名为X-CSRFToken

headers: {'X-CSRFToken': $.cookie('csrftoken')}

  • b. 后端设置

手动调用 csrf 中的 get_token(request)rotate_token(request) 方法

py 复制代码
from django.middleware.csrf import get_token ,rotate_token
 
def server(request):
 
    # get_token(request)       // 两者选一
    # rotate_token(request)   // 此方法每次设置新的cookies

使用装饰器设置

py 复制代码
from django.views.decorators.csrf import csrf_exempt,csrf_protect

csrf_protect是强制验证,在 csrf middleware未被注册时,依然可以强制csrf校验


#csrf_protect 可以使用默认的3种加装装饰器的方法
#csrf_exempt 只可以给dispatch加

参考 csrf原理以及前后端分离如何写入csrf_token blog.csdn.net/qq_41000891...

设置cookie的samesite属性

参考 zh.javascript.info/cookie#shu-...)

Cookie 的 samesite 选项提供了另一种防止此类攻击的方式,(理论上)不需要要求 "XSRF 保护 token"。

它有两个可能的值:

  • samesite=strict(和没有值的 samesite 一样)

如果用户来自同一网站之外,那么设置了 samesite=strict 的 cookie 永远不会被发送。

换句话说,无论用户是通过邮件链接还是从 evil.com 提交表单,或者进行了任何来自其他域下的操作,cookie 都不会被发送。

如果身份验证 cookie 具有 samesite 选项,那么 XSRF 攻击是没有机会成功的,因为来自 evil.com 的提交没有 cookie。因此,bank.com 将无法识别用户,也就不会继续进行付款。

这种保护是相当可靠的。只有来自 bank.com 的操作才会发送 samesite cookie,例如来自 bank.com 的另一页面的表单提交。

虽然,这样有一些不方便。

当用户通过合法的链接访问 bank.com 时,例如从他们自己的笔记,他们会感到惊讶,bank.com 无法识别他们的身份。实际上,在这种情况下不会发送 samesite=strict cookie。

我们可以通过使用两个 cookie 来解决这个问题:一个 cookie 用于"一般识别",仅用于说 "Hello, John",另一个带有 samesite=strict 的 cookie 用于进行数据更改的操作。这样,从网站外部来的用户会看到欢迎信息,但是支付操作必须是从银行网站启动的,这样第二个 cookie 才能被发送。

  • samesite=lax

一种更轻松的方法,该方法还可以防止 XSRF 攻击,并且不会破坏用户体验。

宽松(lax)模式,和 strict 模式类似,当从外部来到网站,则禁止浏览器发送 cookie,但是增加了一个例外。

如果以下两个条件均成立,则会发送含 samesite=lax 的 cookie:

  1. HTTP 方法是"安全的"(例如 GET 方法,而不是 POST)。

    所有安全的 HTTP 方法详见 RFC7231 规范。基本上,这些都是用于读取而不是写入数据的方法。它们不得执行任何更改数据的操作。跟随链接始终是 GET,是安全的方法。

  2. 该操作执行顶级导航(更改浏览器地址栏中的 URL)。

    这通常是成立的,但是如果导航是在一个 <iframe> 中执行的,那么它就不是顶级的。此外,用于网络请求的 JavaScript 方法不会执行任何导航,因此它们不适合。

所以,samesite=lax 所做的是基本上允许最常见的"前往 URL"操作携带 cookie。例如,从笔记中打开网站链接就满足这些条件。

但是,任何更复杂的事儿,例如来自另一个网站的网络请求或表单提交都会丢失 cookie。

如果这种情况适合你,那么添加 samesite=lax 将不会破坏用户体验并且可以增加保护。

总体而言,samesite 是一个很好的选项。

但它有个缺点:

  • samesite 会被到 2017 年左右的旧版本浏览器忽略(不兼容)。

因此,如果我们仅依靠 samesite 提供保护,那么在旧版本的浏览器上将很容易受到攻击。

但是,我们肯定可以将 samesite 与其他保护措施一起使用,例如 XSRF token,这样可以多增加一层保护,将来,当旧版本的浏览器淘汰时,我们可能就可以删除 xsrf token 这种方式了。

5. 误区 误以为攻击者可以读取cookie

初步了解CSRF会发现,攻击者可以获取cookie,便认为从cookie里取token放在header里是脱裤子放屁,多此一举 , 其实攻击者根本无法读取cookie里面的详细信息,只能让浏览器自动携带请求而已。

所以我们最后直接比对cookie中的csrf token 和header里的csrf token即可知道有没有遭受攻击

为什么攻击者无法读取cookie原因是浏览器的同源策略

6. 后端开发必踩的坑,关于自定义响应头的问题

自定义响应头,默认前端无法获取

py 复制代码
return DetailResponse(data=ser.data, msg="获取成功",headers={
    'token': 'no-st4444555','Access-Control-Expose-Headers':'token'})
    
    Access-Control-Expose-Headers
 指定允许访问的自定义头信息。
相关推荐
后端码匠1 小时前
Spring Boot3+Vue2极速整合:10分钟搭建DeepSeek AI对话系统
人工智能·spring boot·后端
CL_IN1 小时前
企业数据集成:实现高效调拨出库自动化
java·前端·自动化
可乐张1 小时前
AutoGen 技术博客系列 (九):从 v0.2 到 v0.4 的迁移指南
后端·llm
可乐张1 小时前
AutoGen 技术博客系列 (八):深入剖析 Swarm—— 智能体协作的新范式
后端·llm
计算机-秋大田1 小时前
基于Spring Boot的农产品智慧物流系统设计与实现(LW+源码+讲解)
java·开发语言·spring boot·后端·spring·课程设计
计算机毕设指导61 小时前
基于SpringBoot的城乡商城协作系统【附源码】
java·spring boot·后端·mysql·spring·tomcat·maven
华子w9089258591 小时前
基于数据可视化+SpringBoot+安卓端的数字化施工项目计划与管理平台设计和实现
java·spring boot·后端
橘猫云计算机设计1 小时前
基于Django的购物商城平台的设计与实现(源码+lw+部署文档+讲解),源码可白嫖!
java·数据库·spring boot·后端·django
2501_903238652 小时前
Spring Boot日志配置与环境切换实战
数据库·spring boot·后端·个人开发
WeiLai11122 小时前
面试基础--微服务架构:如何拆分微服务、数据一致性、服务调用
java·分布式·后端·微服务·中间件·面试·架构