一次安全测试引发的对Django框架文件上传安全机制的初步分析

0×00. 起因

我司的堡垒机是基于jumpserver 0.3版本进行二次开发,进行了大量的重构和新功能的添加,基本满足了公司安全运维的需求。在对文件上传接口进行安全审计的时候发现,其对上传文件名没有过滤处理,然后直接写入磁盘(部分代码如下)

隐隐觉得可以搞搞任意文件写入漏洞(jumpserver web 控制面板都是以root权限运行,如果可以任意文件写入,危害呵呵,你懂得)。启动burpsuite ,拦截请求,修改文件名(含有目录穿越字符),但是结果没成功,调试发现upload_file.name 已经是../../等目录穿越字符过滤后的结果,有点奇怪,莫非是框架自动帮我过滤掉了,好奇心驱使我必须弄明白其中的原理,于是有了本文。

0×01. 分析过程

切入点就是request.FILES 对象的由来,整个流程涉及到5个模块,如下:

跟进parse_file_upload方法(这里的data为WSGIRequest 的实例),如下:

这里要先说下upload_handlers 成员,如下:

默认就是指的红框中的两个文件处理器,大于2.5M的就用TemporaryFileUploadHandler 处理器,否则用MemoryFileUploadHandler。

图中的old_filed_name 即为上一个解析完毕的文件,跟进handle_file_complete ,如下:

跟进文件处理器的file_complete方法, 这个方法返回的就是处理后的文件对象,也就是0×00 图中upload_file 变量指向的文件对象,这里我们以MemoryFileUploadHandler 文件处理器为例进行说明:

也就是说0×00 中的upload_file 也即InMemoryUploadedFile 类的实例,所以调用upload_file.name 即调用InMemoryUploadedFile 的name属性,如下:

调用InMemoryUploadedFile 的name属性,即调用_get_name方法,在InMemoryUploadedFile 实例话的过程中有name的赋值操作(在其父类__init__方法中)如下:

赋值操作就会触发_set_name方法的执行:

0×02. 总结

梳理完成之后,终于对Django 文件上传中的安全机制有了一些了解,解决了我的困惑,像Django 这种现代的web框架对传统的安全漏洞(比如XSS,CSRF、文件上传等)都做了比较好的处理,在开发中,这些都是值得我们借鉴和学习的地方。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180911B0QRRM00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券