文件上传漏洞是Web应用中最危险的安全漏洞之一,攻击者通过绕过上传限制可获取服务器控制权。防御的核心在于服务器端校验与文件类型白名单,而非仅依赖前端校验。据统计,OWASP Top 10报告中,文件上传漏洞常与不安全的文件上传功能相关,导致远程代码执行等严重后果。
前端校验绕过是最简单的绕过方式,因为攻击者可以直接禁用JavaScript或修改请求。常见的前端校验包括检查文件扩展名、文件大小等,但所有客户端校验都可以被绕过。例如,攻击者使用Burp Suite拦截上传请求,修改文件内容为恶意代码,同时保留合法的扩展名,即可绕过前端限制。
代码示例:以下是一个典型的前端校验代码,仅检查扩展名,但服务器端未做任何校验:
function validateFile() {
var file = document.getElementById('upload').files[0];
var allowed = ['jpg','png','gif'];
var ext = file.name.split('.').pop().toLowerCase();
if(allowed.indexOf(ext) === -1) {
alert('Invalid file type');
return false;
}
return true;
}
攻击者只需直接向服务器端发送POST请求,跳过此JavaScript即可。因此,服务器端校验是强制性的。
MIME类型绕过是另一种常见手法,攻击者通过修改HTTP请求中的Content-Type字段来伪装文件类型。例如,上传一个PHP文件,将Content-Type改为image/jpeg,服务器端如果仅检查MIME类型而未检查文件内容,则可能被绕过。据PortSwigger《Web Security Academy》报告,此类绕过在文件上传漏洞中占比约30%。
防护措施:应该在服务器端使用finfo函数或类似方法检测文件的实际MIME类型,例如以下PHP代码:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
if ($mime !== 'image/jpeg' && $mime !== 'image/png' && $mime !== 'image/gif') {
die('Invalid file type');
}
文件扩展名绕过是最具威胁性的手法,攻击者通过双扩展名(如shell.php.jpg)、空字节截断(如shell.php%00.jpg)或利用服务器解析漏洞(如Apache的AddHandler配置)来执行恶意脚本。例如,在Apache中,如果配置了AddHandler application/x-httpd-php .php,那么上传一个名为shell.php.txt的文件,如果服务器将.txt作为PHP执行,则可能导致代码执行。这类漏洞在真实环境中频繁出现。
防护策略:采用白名单机制,只允许确定的扩展名,并对上传文件进行重命名,使用随机生成的文件名,避免用户控制扩展名。同时,将上传目录权限设置为不可执行,例如在.htaccess中禁用PHP执行:
<FilesMatch "\.(php|phar|phtml)$">
Order Allow,Deny
Deny from all
</FilesMatch>
| 绕过手法 | 攻击难度 | 常见场景 | 防护措施 |
|---|---|---|---|
| 前端校验绕过 | 低 | 仅前端校验的上传点 | 服务器端校验 |
| MIME类型绕过 | 中 | 仅检查Content-Type的接口 | 文件内容校验 |
| 扩展名绕过 | 高 | 依赖解析漏洞或黑名单过滤 | 白名单+重命名+目录权限 |
即使部署了WAF,攻击者仍可通过编码、大小写混淆、特殊字符等方式绕过。例如,对文件名进行URL编码,或使用双写绕过扩展名检测。据Cloudflare《WAF Bypass Techniques》报告,大约40%的WAF配置存在被绕过的风险。常见的绕过方法包括:
防御者需要不断更新WAF规则,并结合服务器端深度校验。
在对遗留代码进行审计时,需重点关注文件上传函数的使用。检查以下方面:
例如,以下代码存在严重漏洞:
$target = "uploads/" . $_FILES['file']['name']; move_uploaded_file($_FILES['file']['tmp_name'], $target);
攻击者可直接上传PHP文件。修复方案:
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$allowed = ['jpg', 'png', 'gif'];
if (!in_array(strtolower($ext), $allowed)) {
die('Invalid extension');
}
$new_name = md5(uniqid()) . '.' . $ext;
move_uploaded_file($_FILES['file']['tmp_name'], "uploads/" . $new_name);
文件上传漏洞的防御不能依赖单一技术,必须结合多种措施。核心原则包括:服务器端校验、白名单机制、文件重命名、目录权限控制、以及使用安全的存储服务。开发者应始终假设攻击者能够绕过任何客户端校验,并在服务器端进行深度防御。定期进行安全审计和渗透测试,确保上传功能不会成为攻击入口。
评论
加载中...