目录遍历漏洞主要源于未经净化的用户输入直接拼入路径,须通过URL解码、basename截断、白名单校验、realpath物理路径验证及open_basedir等环境限制进行多层防御。

用 mkdir() 创建用户目录时,路径遍历漏洞主要来自**未经净化的用户输入直接拼入路径**。只要用户能控制目录名或路径片段,就可能传入 ../、%2e%2e%2f、全角点、符号链接等绕过手段。核心不是“怎么调用 mkdir”,而是“怎么确保传给 mkdir 的路径绝对安全”。
只取文件名,不用原始路径
用户提交的目录名(如表单字段 dirname=../../etc)不能原样使用。必须剥离所有路径成分,只保留合法的纯名称:
- 先对输入做
urldecode(),防止 URL 编码绕过(如%2e%2e%2f) - 再用
basename()截断,例如basename(urldecode($_POST['dirname']))→ 得到etc - 最后用正则白名单校验:只允许字母、数字、下划线、短横线,长度限制(如 1–64 字符),拒绝点号、斜杠、空字节、Unicode 异常字符
构造绝对路径后强制校验真实位置
即使文件名干净,攻击者仍可能通过符号链接、挂载点或服务器配置让路径解析出预期外的位置。必须用 realpath() 确认物理路径归属:
- 定义一个明确的、绝对的根目录常量,比如
define('USER_DIR_ROOT', '/var/www/users'); - 拼接目标路径:
$target = USER_DIR_ROOT . '/' . $safe_name; - 调用
$real_target = realpath($target);,并检查:
–$real_target !== false(路径存在且可访问)
–strpos($real_target, realpath(USER_DIR_ROOT)) === 0(真实路径确实在授权根目录内)
创建前检查父目录权限与存在性
mkdir() 默认不递归创建父级,若父目录缺失或不可写,会失败。但更关键的是——不能让攻击者利用父目录权限缺陷间接越权:
立即学习“PHP免费学习笔记(深入)”;
- 确保
USER_DIR_ROOT本身权限合理(如属主为 web 进程用户,组/其他无写权限) - 创建时显式指定
0755权限,避免依赖系统umask导致意外宽松(如0777) - 启用
$recursive = true仅当业务确实需要多级结构,且每级都经上述路径校验 - 创建后立即用
is_dir() + is_writable()双重确认,失败则清理并报错
运行环境层面加固
代码层防护再严密,也需配合 PHP 和 Web 服务器配置堵住底层缺口:
- 在
php.ini中设置open_basedir = /var/www:/tmp,限制 PHP 只能访问指定路径 - 关闭危险功能:
allow_url_fopen = Off、allow_url_include = Off - Web 服务器(如 Nginx/Apache)禁用用户目录下的脚本执行权限,例如对
/users/目录禁止.php解析 - 上传目录和用户目录分离,避免用户目录被当作上传入口



















