Django csrf 的源码流程和分析中间件怎么预防 CSRF 攻击

2 篇文章 0 订阅

通过分析中间件 django\middleware\csrf.py 中的 process_view 的流程:

  1. 在 settings.py 中 ‘django.middleware.csrf.CsrfViewMiddleware’ 中间件被启用,才会走到上述文件

  2. 读取 请求中的 cookie 的 settings.CSRF_COOKIE_NAME 即 csrftoken ,赋值给 csrf_token

  3. 尝试读取 请求中的 csrfmiddlewaretoken 赋值给 request_csrf_token:
    request_csrf_token = request.POST.get(‘csrfmiddlewaretoken’, ‘’)
    (这是为了能处理: 通过模板渲染的表单提交 POST 请求的情况)
    如果没读取到,则会读取请求头中的 HTTP_X_CSRFTOKEN (这是为了能处理: 通过 js 代码,发送 POST 请求的情况)
    注:Django 框架会把原请求头中的 X-CSRFToken 封装为 HTTP_X_CSRFTOKEN

  4. 然后比较 request_csrf_token 和 csrf_token 是否一样,一样的话就可以通过 crsf 的检查。

结论:说白了比较的就是比较 (cookie 中 csrftoken 的值) 和 (纯表单提交中的csrfmiddlewaretoken 或 JS 发的请求头中的 X-CSRFToken)的值是否一样
整个过程根本没有和数据库中的什么比较。
所以前后端分离后即后端没有了模板渲染, 如果前端要发 POST 请求(指的是 js 发 POST 请求),
需要前端工程师手动的在请求头中添加 X-CSRFToken,对应的值通过 js 读 cookie 取到

基于上述结论:你完全可以通过代码构造请求来满足上述的检查,而请求头的 cookie 中的 csrftoken 和 和请求头的 X-CSRFToken 的值可以随意填写

url = "http://192.168.56.101:8082/data/student_data/"
input_dict = {'name':'cheng', 'age':23}
res = requests.post(url, data=input_dict,
					# headers={'X-CSRFToken':'F0S0sHIXOAF9pjwpn78EB5ZjxvOO4c7I','Cookie': 'csrftoken=F0S0sHIXOAF9pjwpn78EB5ZjxvOO4c7I'})
					headers={'X-CSRFToken':'mycsrftokenabc','Cookie': 'csrftoken=mycsrftokenabc'})
print 'type(res.headers) = {0}, res.headers = {1}'.format(type(res.headers), res.headers)
print 'type(res.text) = {0}, res.text = {1}'.format(type(res.text), res.text)
print 'res.status_code = {0}'.format(res.status_code)

在了解了 Django 框架的 CSRF 的认证机制后,来谈一下该机制怎么规避 CSRF 攻击:
CSRF攻击攻击原理及过程如下:

  1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
  2. 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
  3. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
  4. 网站B接收到用户请求后,返回一些攻击性代码(更准确的说是静态资源 < img src=“http://domain A/eg_tulip.jpg” />),并发出一个请求要求访问第三方站点A;
  5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

注意看第 5 步:
攻击代码携带网站 A 的 cookie 信息向网站 A 发送请求(因为攻击代码是运行在浏览器里的,所以当向网站A 发送请求时自然会携带上网站 A 的 cookie即携带了 sessionid 和 crsftoken):
如果在 Django 的后端使能了 django.middleware.csrf.CsrfViewMiddleware 中间件,则该请求就会被终止(虽然 sessionid 是准确的)。
因为 POST 请求中没有携带 csrfmiddlewaretoken ,而请求头的 cookie 中带有 csrftoken。
所以后端获取不到 csrfmiddlewaretoken;然后尝试去请求头中获取 HTTP_X_CSRFTOKEN ,也没有获取到值,
所以自然和 cookie 中的 crsftoken 比较就会失败即请求失败!

你可能会说:我直接手动代码模拟 POST 请求(像上面的 demo 一样,在请求头中写入自己随意编写的 crsftoken 和 HTTP_X_CSRFTOKEN),这样请求也会失败,因为你这样操作虽然能避开 django.middleware.csrf.CsrfViewMiddleware 中间件的检查,但是由于请求中没有 sessionid (因为你的代码是运行在本地的,所以没办法知道网站 A 的 sessionid 是什么。当然假设你不能 F12 查看合法用户访问网站 A时的浏览器), 所以会失败在 session 验证这一步。

也许你会想过有没有一种办法可以让 js 代码把 网站 A 的 cookie 里的内容,发给网站 B?其实是没有的,这是因为浏览器层面有隔离。

所以现在看起来 Django 框架还是很严谨的哦,通过在浏览器的 cookie 中写入 crsftoken 和 sessionid 双认证来确保网站的安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值