记一次文件名触发SQL注入的漏洞测试
字数 992 2025-08-06 21:48:48
文件名触发SQL注入漏洞分析与防御教学
漏洞概述
本案例展示了一个通过文件名触发SQL注入的安全漏洞,揭示了在文件上传功能中,开发者往往忽视了对文件名的严格过滤,导致攻击者可以通过构造恶意文件名实现SQL注入攻击。
漏洞发现过程
-
初始测试:测试人员发现一个文件上传入口,尝试在文件名中插入XSS Payload:
">.png -
XSS触发:XSS漏洞成功执行,但属于Self-XSS(危害有限)
-
错误信息暴露:关闭弹窗后发现数据库错误信息,表明文件名被直接插入数据库查询
-
SQL注入验证:测试人员尝试以下Payload验证SQL注入:
--sleep(15).png--sleep(6*3).png--sleep(25).png--sleep(5*7).png
后端代码分析
根据测试结果推测的后端实现代码(PHP):
$target_dir = "uploads/"; // 存放文件的目录
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]); // 上传后的文件路径
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); // 文件名扩展小写
// 检查图片格式是否是真实图片
if(isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if($check !== false) {
echo "File is an image - " . $check["mime"] . ".";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
}
漏洞根源
- 缺乏文件名验证:代码没有对文件名进行有效性检查
- 直接拼接SQL:文件名被直接用于数据库操作,没有参数化查询或转义
- 错误信息暴露:数据库错误信息直接返回给用户
修复方案
1. 文件名验证
$filename = $_FILES["fileToUpload"]["name"];
if (preg_match('/^[\/\w\-. ]+$/', $filename)) {
echo 'VALID FILENAME';
} else {
echo 'INVALID FILENAME';
$uploadOk = 0;
}
2. 数据库安全措施
- 使用参数化查询(预处理语句)
- 对用户输入进行适当的转义
- 限制数据库错误信息显示
3. 其他防御措施
-
文件名规范化:
- 使用白名单验证文件扩展名
- 重命名上传文件(如使用随机名称)
-
文件内容验证:
- 验证文件真实类型(不只是扩展名)
- 检查文件内容是否匹配其类型
-
权限控制:
- 限制上传目录的执行权限
- 设置适当的文件权限
漏洞利用扩展
虽然案例中只展示了时间盲注,但理论上可以尝试:
- 联合查询注入:获取数据库信息
- 布尔盲注:通过条件判断获取数据
- 堆叠查询:执行多条SQL语句
安全开发建议
- 最小权限原则:数据库账户使用最小必要权限
- 输入验证:所有用户输入都应视为不可信的
- 防御深度:实施多层防御措施
- 错误处理:自定义错误页面,避免泄露敏感信息
- 安全编码:使用ORM框架或参数化查询
总结
此案例展示了几个关键安全原则:
- 所有用户输入都是不可信的:包括看似无害的文件名
- 细节决定安全:看似微小的疏忽可能导致严重漏洞
- 防御需要多层次:单一防御措施往往不足
- 错误处理的重要性:不当的错误处理会泄露系统信息
通过这个案例,开发人员和安全测试人员都应认识到,安全是一个系统工程,需要从设计到实现的每个环节都保持警惕。