前言
上网过程中,我们经常会将一些如图片、压缩包之类的文件上传至文件服务器进行保存。而文件上传攻击指的是攻击者利用一些站点没有对文件的类型做很好的校验,上传了可执行的文件或脚本,并且通过脚本获得服务器上相应的权限,或者是通过诱导外部用户访问下载上传的病毒或木马,达到攻击的目的。
除了上述危害,我们还需防止用户将文件服务器当成免费的网盘无限制上传文件。
解决方案
- 文件类型白名单校验(仅允许部分文件类型上传)
- 限制文件大小
- 服务器存储时重命名文件,攻击者无法预测文件访问路径
准确的校验文件类型
我们显然不能简单的通过后缀来识别文件类型,这无法达到最终的防范目的。
而是应该通过文件的起始字节流来判断,因为大部分类型文件(xlsx/png/jpg/gif)的起始字节流是固定的,根据它可以准确的判断文件类型,据书中介绍,这几个字节也称为魔数。书中给的是Java的示例,我在这里给出Python的示例,原理很简单,你可以用你熟悉的语言做到。
Python示例:
"""
通过文件头判断文件类型
"""
import binascii
path = r'C:\Users\L\Desktop\demo.gif'
# 常见的文件类型魔数
file_header = {
'jpg': b'ffd8ff',
'gif': b'47494638',
'png': b'89504e37',
'xlsx':b'504b0304', # excel
'tiff': b'49492a00',
'bmp': b'424d',
'dwg': b'41433130', # CAD
'psd': b'38425053', # ps
'xml': b'3c3f786d6c',
'html': b'68746d6c3e',
'pdf': b'255044462d312e',
'zip': b'504b0304',
'rar': b'52617221',
'wav': b'57415645',
'avi': b'41564920'
}
def judge_file_type(path, ftype='jpg')->bool:
with open(path, 'rb')as f:
s = f.read(28)
s = binascii.b2a_hex(s)
print(s, binascii.b2a_hex(s))
return s.startswith(file_header[ftype])
print(judge_file_type(path,'jpg'))
注意:代码中关于魔数部分摘抄自《大型分布式网站架构设计与实践》一书,博主并没有进行大量的测试,如读者要用于生产环境,请做好测试工作。