PHP实际场景中如何修复I/O函数存在的路径注入攻击漏洞
漏洞修复方案
你的代码存在路径遍历高危漏洞,攻击者可通过传入带../的文件名向服务器任意路径写入文件,即使是内部使用场景也存在被恶意利用的风险。此外你原有代码中strlen($$_GET["output_file"])存在笔误,多写了一个$形成可变变量,本身也会产生额外安全风险。
一、白名单校验修复方案(符合SonarQube要求)
核心原则
- 固定存储根目录,完全禁止用户控制文件存储的路径部分
- 仅对文件名做白名单字符校验,严格限制允许的字符和后缀
- 最终路径二次校验,确保不会跳出指定存储目录
修复后代码示例
// 1. 定义固定的PDF存储根目录(必须用绝对路径,提前给程序开放写入权限) define('PDF_STORAGE_PATH', '/data/app/internal_pdf_output/'); // 2. 修正原有参数校验的笔误,去掉多余的$ if(!empty($_GET["output_file"]) && is_string($_GET["output_file"]) && strlen($_GET["output_file"]) > 0 ) { $input_filename = rawurldecode($_GET["output_file"]); // 3. 只取文件名部分,过滤掉所有路径分隔符和上层目录标识 $input_filename = basename($input_filename); // 4. 白名单校验:仅允许中文、大小写字母、数字、下划线、中划线、点,且后缀必须为.pdf if (!preg_match('/^[\x{4e00}-\x{9fa5}a-zA-Z0-9_\-\.]+\.pdf$/u', $input_filename)) { die("文件名不合法,仅允许中文、字母、数字、下划线、中划线,且必须为pdf后缀"); } // 5. 拼接完整存储路径 $outfile = PDF_STORAGE_PATH . $input_filename; // 6. 二次校验最终路径是否在指定存储目录下,防止编码绕过 $real_outpath = realpath(dirname($outfile)); if ($real_outpath !== rtrim(PDF_STORAGE_PATH, DIRECTORY_SEPARATOR)) { die("非法路径请求"); } // 7. 写入文件 file_put_contents($outfile, $dompdf->output()); }
二、兼顾自定义文件名需求的更安全方案
如果希望进一步降低风险,同时完全满足用户自定义文件名的需求,可以采用「服务器存储名+下载映射」的方案:
- 服务器侧存储的文件名使用完全可控的规则生成,比如
用户ID_时间戳_随机6位字符串.pdf,完全避免用户输入影响存储路径 - 在数据库中记录用户ID、自定义文件名、服务器存储路径的映射关系
- 用户下载文件时,通过
Content-Disposition响应头将文件名设置为用户自定义的名称,用户感知完全不受影响
示例下载逻辑:
// 从数据库查询对应的自定义文件名和存储路径 $custom_name = $file_info['user_custom_name']; $storage_path = $file_info['storage_path']; header('Content-Type: application/pdf'); header('Content-Disposition: attachment;filename="' . rawurlencode($custom_name) . '"'); readfile($storage_path);
该方案完全规避了用户输入对存储路径的影响,安全性更高,同时完全满足用户自定义文件名的需求。
内容的提问来源于stack exchange,提问作者mahen3d
相关产品推荐
相关产品推荐

