本文最后更新于23 天前,其中的信息可能已经过时,如有错误请发送邮件到 [email protected]
站点跑了几个月,访问一切正常,直到有人在日志里看到一条奇怪的请求:
GET /srvcard/btapi_configured.php.bak-dual-20261007 200 9828
问题出在哪
nginx 的 PHP 规则写的是:
location ~ \.php$ {
fastcgi_pass unix:/tmp/php-cgi-82.sock;
}
它只匹配以 .php 结尾的文件。btapi_configured.php.bak-dual-20261007 不满足这个条件,于是落到了 location / 的静态文件处理分支——nginx 把它当成普通文本,原样返回。
更糟的是,PHP 文件里通常写着配置:
面板 API 密钥、数据库账号口令、第三方 token,全都在这类文件里。
怎么确认范围
不要只看一个链接。按后缀扫一遍 webroot:
find /var/www /www/wwwroot -type f \
\( -name '*.bak*' -o -name '*.sql' -o -name '*.db' \
-o -name '*.old' -o -name '*.swp' -o -name '*~' \) | wc -l
结果 47 个。全部可下载。
处置顺序
- 先把文件移出 webroot,不要就地删——保留目录结构放进
/root/webroot-quarantine-<日期>/,随时能还原。 - 再补一条全局规则,防止下次再犯:
location ~* \.(bak|old|orig|save|swp|tmp|sql|db|sqlite3?|log|lock|inc|cnf|ini|dist|example)([._-][^/]*)?$ {
deny all;
}
- 最后轮换所有曾被暴露的密钥。文件不可下载了,不代表密钥还安全——它已经在公网待了很久。
两个容易忽略的坑
- 默认站(
server_name _)往往没人维护。如果它的location ~ \.php$被注释掉了,任何未匹配的域名都会命中它,PHP 源码直接明文输出。 - 正则里的
~*优先级高于普通前缀 location,但低于^~。所以/srvcard/这种^~前缀不会被覆盖,需要单独确认。
收尾验证用不存在的路径探针最直观:请求 /__probe.bak,返回 403 才说明规则真的生效;返回 404 说明这个 server 块根本没配上。
