必须白名单校验用户输入的文件名或路径参数,禁止直接拼接;应建立静态映射表(如$type→绝对路径),仅通过键查找获取路径;若键不存在则返回403并记录日志;动态解析时须三重防护:basename()提取文件名、正则限制格式、realpath()校验是否在授权目录内;禁用allow_url_fopen、allow_url_include,启用open_basedir限制访问范围;Web服务器层拦截../等危险特征,禁用eval等高危函数,关闭错误信息显示。

输入必须白名单校验
用户传入的文件名或路径参数绝不能直接拼接进文件操作函数。应建立静态映射表,只允许预设的合法标识符,例如:
- 定义数组:
$allowedFiles = ['report' => '/var/www/data/reports/monthly.pdf', 'config' => '/var/www/conf/app.yaml']; - 接收参数后仅用作键查找:
$fileKey = $_GET['type'] ?? ''; $path = $allowedFiles[$fileKey] ?? null; - 若键不存在或路径为空,立即返回403并记录日志,不执行任何读取操作。
路径必须规范化并严格约束范围
当业务确实需动态解析文件名(如附件下载),必须做三重防护:
- 用
basename()提取纯文件名,剥离所有路径符号; - 用正则限制格式,例如
/^[a-zA-Z0-9._-]+\.pdf$/,禁止点号开头、双扩展名、空字节等; - 拼接基础目录后调用
realpath(),再检查结果是否仍落在授权目录内,例如:$real = realpath($baseDir . $safeName); if (strpos($real, $baseDir) !== 0) { die('Access denied'); }
禁用危险协议与全局限制访问边界
PHP默认支持 php://filter、phar://、file:/// 等协议,它们是任意文件读取升级为源码泄露甚至RCE的关键跳板:
- 在
php.ini中设置:allow_url_fopen = Off和allow_url_include = Off; - 启用
open_basedir,明确限定脚本可访问的根路径,如:open_basedir = "/var/www/html:/tmp"; - 确保上传目录、临时目录、session 存储路径都包含在该范围内,避免功能异常。
运行时拦截与纵深防御
代码层加固之外,还需叠加基础设施防护:
立即学习“PHP免费学习笔记(深入)”;
- 在 Web 服务器(Nginx/Apache)或 API 网关层,配置规则拦截含
../、%2e%2e%2f、etc/passwd、.env等特征的请求; - 禁用
eval、assert、system等高危函数,通过disable_functions统一管控; - 关闭错误信息对外显示(
display_errors = Off),防止路径、结构等敏感线索泄露。



















