PHP如何防范不同用户类型越权访问upload目录下对应子文件夹资源
防范越权访问私有上传资源的可行方案
方案1:将上传目录移出Web可访问根目录(最推荐)
- 把整个
upload文件夹移动到站点Web根目录之外,比如你的站点根目录是/www/wwwroot/your_site/public,就把upload放到/www/wwwroot/your_site/upload路径下,这样外部用户无法通过URL直接访问到该目录下的任何文件 - 新增一个PHP中间层来处理文件读取请求,示例逻辑如下:
// 统一资源访问路径为 get_file.php?f=2/something.png 格式 session_start(); // 先校验用户登录状态 if(!isset($_SESSION["u_type"])){ http_response_code(403); exit("无权访问"); } $request_file = $_GET['f']; // 路径合法性校验,防止目录穿越攻击 if(str_contains($request_file, '..') || !preg_match('/^\d+\/[\w\-\.]+$/', $request_file)){ http_response_code(400); exit("非法请求"); } // 提取资源所属用户类型,和当前登录用户类型比对 $file_user_type = intval(explode('/', $request_file)[0]); if($file_user_type != $_SESSION["u_type"]){ http_response_code(403); exit("无权访问该资源"); } // 拼接web根目录外的实际文件路径 $real_path = "/www/wwwroot/your_site/upload/".$request_file; if(!file_exists($real_path)){ http_response_code(404); exit("文件不存在"); } // 输出文件内容 $finfo = new finfo(FILEINFO_MIME_TYPE); header("Content-Type: ".$finfo->file($real_path)); readfile($real_path); - 原有页面中的资源引用全部改成指向这个中间层的路径,比如原来的
<img src="uploads/2/something.png"/>改成<img src="get_file.php?f=2/something.png"/>即可。
方案2:在Web服务器层做权限校验(适合不想调整现有文件读取逻辑的场景)
如果不想把文件移出Web目录,也可以用Nginx的auth_request模块或者Apache的mod_authz_core模块,配合PHP权限校验接口实现访问控制:
- Nginx配置示例逻辑:
location ^~ /uploads/ { auth_request /auth_file_access; } location = /auth_file_access { internal; fastcgi_pass unix:/run/php-fpm.sock; fastcgi_param SCRIPT_FILENAME /www/wwwroot/your_site/public/auth_file_access.php; include fastcgi_params; } - 编写
auth_file_access.php,逻辑和方案1里的权限校验部分一致,校验通过返回200状态码,不通过返回403状态码即可。
方案3:给静态资源添加无法枚举的随机前缀(临时补救方案)
如果以上两种方案改造成本太高,可以作为临时过渡方案使用:
- 给每个用户类型的子目录添加一段16位以上的无规律随机字符串后缀,比如类型2的子目录路径改成
uploads/2_8f3d92kf7e4j6h1g/,每个用户类型的随机串唯一且不对外暴露 - 注意该方案只能降低资源被恶意遍历访问的概率,不能从根本上解决越权问题,不建议长期使用。
内容的提问来源于stack exchange,提问作者Bálint Cséfalvay
相关产品推荐
相关产品推荐

