PHP路径安全需设open_basedir限制目录、用Web服务器规则屏蔽敏感路径、避免realpath与符号链接冲突、弃用__FILE__依赖SCRIPT_FILENAME的日志和路由逻辑,并统筹部署权限与访问控制。

PHP中用open_basedir限制真实路径暴露
不设open_basedir,攻击者通过include、file_get_contents等函数配合错误回显,很容易猜出服务器绝对路径(比如/var/www/html/app/config.php)。这不是理论风险——很多CMS被拖库前都先爆出了DocumentRoot。
实操建议:
- 在
php.ini或虚拟主机配置里明确设置open_basedir = /var/www/html:/tmp,只放开必要目录 - 避免写成
open_basedir = /var/www——子目录太多反而扩大攻击面 - 启用后注意
getcwd()返回的是受限后的“根”,不是系统真实路径;依赖__DIR__做路径拼接的代码要重新验证 - Apache下用
php_admin_value open_basedir比.htaccess更可靠,后者可能被覆盖
用mod_rewrite屏蔽敏感文件直接访问
用户请求/config/database.php时,Apache默认会尝试返回该文件内容——哪怕PHP没执行,也可能泄露明文配置。这不是PHP的问题,但PHP项目常因此被连带拖垮。
实操建议:
- 在
.htaccess或vhost配置中加规则:RewriteRule ^(?:config|app|storage)/.* - [F,L]
- 别只拦
.php后缀——.env、.log、.bak同样危险,规则要覆盖扩展名和目录名 - Nginx用户对应用
location ~ ^/(config|app|storage)/ { return 403; } - 测试时用
curl -I http://yoursite.com/config/database.php确认返回403而非200或500
realpath()和dirname(__FILE__)混用导致路径映射失效
有些开发者以为用realpath(__DIR__ . '/../public')就能安全定位Web根目录,结果在符号链接部署(如/var/www/current → /var/www/releases/20240501)下,realpath()返回的是物理路径,而Web服务器只认current这个逻辑入口——路径映射就断了。
实操建议:
- 优先用
$_SERVER['DOCUMENT_ROOT']获取Web根目录,它由Web服务器提供,天然匹配虚拟路径 - 如果必须用
__DIR__,就别套realpath(),改用dirname(dirname(__DIR__))这类纯字符串操作 - 检查
include_path是否含.——这会让require 'Config.php'从当前工作目录开始找,极易越权读取 - 用
get_included_files()调试时,留意输出里有没有意外包含的非预期路径
伪静态路由下$_SERVER['SCRIPT_FILENAME']不再可靠
当用index.php统一入口(如Laravel、ThinkPHP),所有请求都指向同一个SCRIPT_FILENAME,这时再用它来判断当前脚本位置,就会误判真实业务路径,导致日志记录错乱、资源加载失败,甚至暴露index.php所在的真实目录。
实操建议:
- 改用
$_SERVER['REQUEST_URI']或框架提供的路由解析结果来判断逻辑路径,而不是依赖SCRIPT_FILENAME - 记录日志时,别写
error_log('Failed in ' . __FILE__);——__FILE__始终是index.php,失去定位价值 - 如果必须定位具体控制器文件,用
debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[1]['file']抓调用栈第二层(但仅限开发环境) - 上线前检查
display_errors=Off且log_errors=On,防止SCRIPT_FILENAME随错误信息一起泄露
路径映射真正的难点不在技术实现,而在「哪些路径该映射」「哪些该彻底屏蔽」的边界判断——比如storage/logs要禁止Web访问,但CLI脚本又要能写入;vendor不能被HTTP读取,却得让composer autoloader正常加载。这些冲突点,光靠一个配置项解决不了,得结合部署结构、运行角色、权限模型一起看。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











