DedeCMS目录禁PHP解析:nginx4步加固方案+24类避坑
织梦 DedeCMS 站点为什么三天两头被挂马?保哥用 nginx 一段 location 配置把 uploads/templets/images/data 等目录的 PHP 解析全部拒绝,挡住 80% 的 webshell 攻击;附 Apache .htaccess 等效配置、文件权限、加固清单、被攻击后应急处置流程。
本文目录
2014 年保哥接手过一个三天两头被挂马的织梦 DedeCMS 站点,每次清理完没几天又被植入新马,最后排查下来根本原因不在 DedeCMS 自身的漏洞,而是攻击者通过编辑器上传图片接口把 木马.php.jpg 这种伪装文件丢到 /uploads/ 目录,再通过路径直接访问 uploads/xxx/shell.php 执行恶意代码。从那以后保哥养成了一个固定习惯:所有 DedeCMS 站点上线第一件事,就是把 uploads、templets、images、html 这类不需要执行 PHP 的目录在 nginx 层 deny 掉 PHP 解析。这一道防线挡住了 80% 以上的 PHP 后门攻击。本文记录这套方案的完整配置、攻击原理、相关安全加固的全套细节。
为什么要禁止特定目录执行 PHP
织梦 DedeCMS 这类老 CMS 之所以挂马频繁,根本原因是"凡是能被上传文件的目录都可能被植入 PHP 后门"。攻击者常见手法有以下几种:
- 编辑器漏洞上传。FCKEditor、UEditor、CKEditor 等富文本编辑器历史上有过若干上传校验绕过漏洞,攻击者通过构造特殊的 Content-Type、Magic Number 把 PHP 文件伪装成图片上传到
/uploads/。 - 文件管理器越权。后台文件管理器如果鉴权不严,攻击者拿到普通用户账号也能传 PHP 到任意目录。
- 会员投稿接口。开放注册的站点,会员投稿往往附带"上传图片"功能,逻辑漏洞同样可能被利用。
- 第三方插件。织梦插件生态早期审核宽松,部分插件自带的上传组件就是后门入口。
- 历史遗留。多年前被入侵留下的后门可能还潜伏在某个图片目录里,没被清干净。
这些攻击手法的共同特征是:把 PHP 代码丢到一个本不该执行 PHP 的目录。如果 web 服务器看到 /uploads/xxx.php 直接交给 PHP-FPM 解析,攻击就成功;如果在 nginx 层就拦截掉,deny all 返回 403,攻击就失败。这就是本文方案的核心思路:白名单思维——只在确实需要 PHP 解析的目录开放,其他目录一律禁止。
宝塔面板 nginx 完整配置
登录宝塔面板,进入对应站点的"配置文件"编辑界面(也可以直接 SSH 编辑 /www/server/panel/vhost/nginx/yourdomain.conf)。在 server { ... } 块内、紧挨着 root 行下面,加入以下配置:
location ~* ^/(include|uploads|a|templets|skin|images|html|data|special)/.*\.(php|php5|php7|phtml|pht)$
{
deny all;
return 403;
access_log off;
log_not_found off;
}这段配置的几个关键细节:
~*是大小写不敏感的正则匹配,能拦住.PHP、.Php这类大小写变体。^/(...)/限定只匹配以这些目录名开头的路径。如果你的站点这些目录有别名或软链,需要把别名也加进来。\.(php|php5|php7|phtml|pht)$覆盖 PHP 解析器可能识别的所有扩展名。.phtml和.pht是历史上被绕过验证常用的扩展,强烈建议一并屏蔽。deny all+return 403双保险,确保不会因为某些 nginx 版本的解析差异让请求漏过去。access_log off减少日志噪音,因为这类请求一旦发生通常是攻击探测,记下来意义不大反而消耗磁盘。
保存配置后宝塔会自动 reload nginx,几秒钟内生效。如果是手动改的 conf 文件,记得 nginx -t 测试语法后 nginx -s reload。
目录清单与责任分工
织梦 DedeCMS 默认目录结构里,建议禁 PHP 的目录及其用途:
- /uploads/:用户上传的图片、附件、文档。100% 不应该执行 PHP。
- /templets/:前端模板文件目录。模板里只有
.htm、CSS、JS、图片,不需要 PHP 解析(DedeCMS 的模板渲染是在编译阶段完成的,渲染后的 HTML 输出文件在别的地方)。 - /skin/:后台皮肤资源(CSS、JS、图片)。
- /images/:站点公用图片资源。
- /html/:DedeCMS 静态生成的 HTML 文件目录(如果开启了静态生成)。
- /a/:DedeCMS 默认的文章静态生成根目录(取决于站点配置)。
- /include/:核心 PHP 文件,但对外不应该暴露访问——所有调用都通过其他入口文件
require_once引入。所以禁止外部直接访问/include/xxx.php是合理的。 - /data/:缓存、备份、临时数据。绝对不能执行 PHP,因为这里有数据库备份文件、敏感配置缓存。
- /special/:专题页目录(如果用了专题功能)。
需要保留 PHP 执行的目录有:根目录入口文件(index.php、list.php、view.php、tag.php 等)、/dede/ 后台目录(建议改名)、/member/ 会员中心、/plus/ 扩展目录(如果在用)。
Apache 环境的等效配置
如果站点跑在 Apache 上,可以通过 .htaccess 实现同样效果。在 /uploads/、/templets/ 等需要禁 PHP 的目录里,分别放一份 .htaccess:
<FilesMatch "\.(php|php5|php7|phtml|pht)$">
Order Deny,Allow
Deny from all
</FilesMatch>Apache 2.4 及以上推荐用新语法:
<FilesMatch "\.(php|php5|php7|phtml|pht)$">
Require all denied
</FilesMatch>Apache 的 .htaccess 方案有两个优势:一是粒度细,每个目录单独控制;二是修改不需要 reload web 服务。劣势是每次请求都会读 .htaccess 文件,性能不如 nginx 集中配置好。如果你的站点流量大且仍在用 Apache,建议把规则迁到主配置文件里减少 .htaccess 解析开销。
文件系统权限配合
nginx 层的 PHP 解析屏蔽是第一道墙,文件系统权限是第二道。两道叠加才稳。织梦 DedeCMS 推荐的目录权限:
- 网站根目录:755(所有者读写执行,其他用户读执行)。
- /data/:750(仅 owner + group 可访问,禁止 other 读取,避免
data/sqldata/*.txt数据库备份被外网爬走)。 - /uploads/:755(PHP-FPM 进程要能写入上传文件)。
- /dede/:755 或 750(后台代码,建议改名为非默认 dede 后再设权限)。
- /include/:755。
- 所有 PHP 文件:644(owner 读写,其他读,禁止任何用户写——攻击者就算上传了 PHP 也无法覆盖现有文件)。
- 所有目录:755(保证 web 进程能进入)。
批量设置命令(在站点根目录执行):
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
chmod -R 750 ./data/
chown -R www:www ./注意 owner 要是 web 服务用户(宝塔默认 www,CentOS 默认 nginx 或 apache)。如果上传写入失败,多半是 owner 错了,chown 修一下即可。
加固清单:除了禁 PHP 还要做的
禁 PHP 是基础线,下面这几项加上去防御就比较完整了:
- 后台目录改名。把
/dede/改成不规则的字符串如/admin_a8x7k2/,再配合 IP 白名单访问,能挡住绝大多数自动化扫描。 - install.php 删除或断网。安装完成后
install/index.php.bak文件务必删掉或加deny all,历史上有大量站点是因为 install 文件没删被攻击者重装。 - plus 目录限制。
/plus/下很多文件是历史漏洞重灾区(如recommend.php、flink_add.php),不需要的功能直接删掉对应文件。 - 禁用 PHP 危险函数。在
php.ini里disable_functions加上exec, passthru, shell_exec, system, proc_open, popen, eval等,即使有后门也无法执行命令。 - open_basedir 限制。把 PHP 进程能访问的文件路径限制在站点根目录内,攻击者无法跨站读 /etc/passwd。
- WAF 接入。宝塔自带的 nginx 防火墙、阿里云 WAF、Cloudflare WAF 任选其一,对常见攻击 payload 做规则拦截。
- 文件完整性监控。AIDE、tripwire 或宝塔的"文件监控"功能,对 PHP 文件做哈希校验,新增/修改文件立即告警。
- 定期备份。代码 + 数据库每周完整备份,备份保留至少 30 天滚动,避免被攻击后无干净版本可恢复。
验证配置是否生效
配置完成后必须验证一遍是否真的生效。验证步骤:
第一步,SSH 登录服务器,在 /uploads/ 目录创建一个测试 PHP 文件:
echo "<?php phpinfo(); ?>" > /www/wwwroot/yoursite/uploads/test_check.php第二步,用浏览器访问 https://yoursite.com/uploads/test_check.php。如果返回 403 Forbidden,说明 nginx 配置生效了;如果返回 phpinfo() 页面,说明配置没生效,需要回查 nginx 配置和 reload 状态。
第三步,访问 /uploads/somepic.jpg 类正常图片,确保 nginx 没误伤——只有 .php 文件被屏蔽,其他文件类型应该正常返回。
第四步,测试完务必删除测试文件:rm /www/wwwroot/yoursite/uploads/test_check.php,避免留隐患。
第五步,把这个测试用例做成脚本,每次 nginx 配置变更后自动跑一次,避免下次有人改 nginx 时把这条规则注释掉了没人知道。
被攻击后的应急处理
如果你接手的站点已经挂马了,光配 nginx 不够,得先清干净。保哥的应急清理流程:
- 立刻断网。在防火墙层把 80/443 端口封掉,阻止攻击者持续访问后门。
- 全站文件备份。打 tar 包带走,留作取证。
- 找出后门文件。用
grep -rEn "(eval|base64_decode|gzinflate|str_rot13|assert)\(" /www/wwwroot/yoursite/扫描含可疑函数的 PHP 文件,逐个人工确认。 - 检查 webshell 特征。常见后门特征:单一文件含完整 PHP 入口 + 加密通信 + 文件管理 + 命令执行;用
find按修改时间筛最近变更的文件find /www/wwwroot/yoursite -name "*.php" -mtime -7。 - 对比官方代码。从 DedeCMS 官方下载同版本干净源码,diff 出所有被改动的文件。
- 清理数据库。后门也可能藏在数据库里(管理员表、文章正文 onload 注入),逐表 SELECT 高危关键字。
- 重置所有密码:管理员账号、数据库密码、SSH 密钥、宝塔面板密码。
- 部署本文配置。nginx deny PHP + 文件权限收紧 + WAF 上线。
- 恢复网络访问,但先内网测试 24 小时确认没有残留后门。
其他 CMS 的等效配置参考
这套思路并非 DedeCMS 独占。其他主流 CMS 的"禁 PHP 目录清单"参考:
- WordPress:
wp-content/uploads/、wp-content/themes/*/assets/等需要禁 PHP。 - Typecho:
usr/uploads/、usr/themes/*/assets/需要禁 PHP。 - Discuz:
data/attachment/、uc_server/data/、data/cache/需要禁 PHP。 - ECShop / ECTouch:
images/、data/、themes/需要禁 PHP。 - 帝国 CMS:
d/file/、d/txt/、d/js/、e/template/需要禁 PHP。 - Drupal / Joomla:
sites/default/files/、images/、media/需要禁 PHP。
所有 CMS 的逻辑都一样:"上传目录、模板资源目录、缓存目录绝对不允许执行 PHP",这是通用安全准则。
监控告警与持续运维
配置完成不代表万事大吉,建议长期开启以下监控:
- nginx access.log 异常 PHP 请求统计。每天用
awk统计/uploads/.*\.php类请求数量,突然飙升说明有人在扫描。 - 403/404 突增告警。如果一夜之间 403 数量从几十涨到几千,多半遇到了自动化攻击。
- 文件改动告警。inotify-tools 或宝塔的文件监控对
/uploads/目录做监听,新增 .php 文件立即告警。 - 登录日志。后台管理员登录、SSH 登录、宝塔面板登录,全部接入告警通道(邮件/钉钉/企业微信)。
- 季度安全审计。每季度跑一次
find / -newer /tmp/last_audit -type f找出近期修改的所有文件,过一遍是否合规。
这些监控加上去,攻击发生时能在 5-30 分钟内发现并响应,远比"被挂马半年才发觉"强得多。
典型攻击案例复盘
保哥这几年实战中处理过的几个典型 DedeCMS 挂马案例,每个都对应了不同的攻击向量,合并起来能帮你建立更完整的防守认知。
案例一:UEditor 类型校验绕过。某地方门户站,攻击者把一个 PHP 后门通过 UEditor 上传接口传到 /uploads/allimg/202309/shell.php。原因是 UEditor 早期版本只校验了 Content-Type 头,没校验文件实际内容,攻击者用 Content-Type: image/jpeg 但 body 里塞 PHP 代码就绕过了。这个案例的关键启示是:不能把上传文件的安全完全交给应用层,nginx 层 deny PHP 是兜底防线。
案例二:plus/recommend.php SQL 注入升级。一个旧 DedeCMS 5.7 站点,攻击者利用 plus/recommend.php 的 SQL 注入漏洞读出管理员账号密码,登录后台后通过"模板管理 → 文件管理"上传 PHP 木马到 /data/cache/ 目录。如果当时已经禁了 /data/ 的 PHP 解析,即使后台被攻入,木马也跑不起来——攻击链就被切断了。
案例三:第三方插件后门。一个使用某"高仿 SEO 插件"的 DedeCMS 站点,插件本身就带了一个隐藏的 webshell 路由 /include/dedeseo/back.php。这种"自带后门"的插件防不胜防,禁 include 目录的 PHP 解析能直接挡住这类攻击。当然 include 目录确实存在被引用的合法 PHP 文件,但这些文件正常使用应该是被 require_once 引入而不是直接 URL 访问,所以禁直接访问没有副作用。
案例四:data 目录敏感文件泄露。一个站点没有禁 /data/ 目录,攻击者直接访问 data/sqldata/dede_admin-id.txt 读到了管理员密码哈希。这个案例展示了 deny 不仅能防止 PHP 执行,对敏感文件的读取保护同样重要。建议把 /data/ 整个目录直接 deny all(不管什么扩展名),写法是:
location ^~ /data/ {
deny all;
return 403;
}这样连 .txt、.sql 备份文件都读不到。
与 ModSecurity / Cloudflare WAF 的分工
有些同学已经接入了 WAF(云 WAF 或 ModSecurity),是不是就不用配本文的 nginx deny 规则了?答案是不行,二者是不同层次的防御:
- WAF:基于流量特征做规则匹配,拦截已知攻击 payload。优点是覆盖广,劣点是规则一旦过时新攻击方式会绕过;且 WAF 默认信任来自服务器内部的请求,如果攻击者已经传了文件到服务器,访问该文件不会经过 WAF(特别是 ModSecurity 装在反代层时)。
- nginx 目录禁 PHP:基于路径/扩展名做静态规则,无论攻击 payload 多新颖,只要 PHP 文件落在被禁目录就跑不起来。
- fail2ban:基于 access.log 模式封 IP,对暴力探测有效但对单次攻击不及时。
- SELinux / AppArmor:操作系统级别的强制访问控制,PHP 进程即使想读 /etc/passwd 也读不到。这层最底,配置最复杂,多数中小站没启用。
四层叠加才是完整防御。本文的 nginx 配置是其中性价比最高的一层——配置简单、零运维成本、对正常业务零影响、却能挡住绝大多数自动化攻击。建议在 WAF 之外一定要加上。
自动化巡检脚本
保哥写了一个简单的 bash 脚本,每天 cron 跑一次,自动检查 nginx 配置和 uploads 目录是否还安全:
#!/bin/bash
SITE_ROOT="/www/wwwroot/yoursite.com"
NGINX_CONF="/www/server/panel/vhost/nginx/yoursite.com.conf"
# 1. 检查 nginx 配置是否还包含 deny 规则
if ! grep -q "deny all" "$NGINX_CONF" || ! grep -q "uploads.*\.php" "$NGINX_CONF"; then
echo "[ALERT] nginx deny 规则缺失"
fi
# 2. 扫描 uploads 目录是否有 PHP 文件
PHP_FILES=$(find "$SITE_ROOT/uploads" -name "*.php" 2>/dev/null)
if [ -n "$PHP_FILES" ]; then
echo "[ALERT] uploads 目录发现 PHP 文件:"
echo "$PHP_FILES"
fi
# 3. 检查近 24 小时被修改的 PHP 文件
RECENT=$(find "$SITE_ROOT" -name "*.php" -mtime -1 2>/dev/null)
if [ -n "$RECENT" ]; then
echo "[INFO] 近 24 小时修改的 PHP 文件:"
echo "$RECENT"
fi把这个脚本放到 /root/daily_check.sh,加 chmod +x,再 crontab -e 里加一行 0 6 * * * /root/daily_check.sh | mail -s "DedeCMS 安全巡检" you@example.com,每天早 6 点出一份巡检报告。任何异常都能在当天发现。
常见问题解答
Q1:配置后图片上传不影响吧?
不影响。这条规则只针对 .php、.phtml 等扩展名,.jpg、.png、.gif、.webp 等正常图片格式不会被拦截。/uploads/ 目录依然可以正常存放和访问图片资源。
Q2:站点本来就靠 /uploads/preview.php 这种文件提供预览功能怎么办?
如果有合法的 PHP 入口在被屏蔽的目录下,需要单独放行。可以在 nginx 配置里加一条更具体的 location = /uploads/preview.php { ...正常 PHP 解析配置... },= 是精确匹配优先级最高,会绕过通用 deny all 规则。但更推荐的做法是把这种 PHP 文件迁出 uploads 目录,从架构上避免开洞。
Q3:宝塔面板的"防跨站攻击"开关跟这个有什么关系?
不一样。宝塔的"防跨站攻击"是 open_basedir 限制,让 PHP 进程不能跨站读其他站的文件。本文方案是 nginx 层不让某些目录的 PHP 被执行,二者是互补关系,建议都开启。
Q4:deny all 和 return 403 选哪个?
都行。deny all 是 ngx_http_access_module 的指令,最终也是返回 403。return 403 是 ngx_http_rewrite_module 的指令,更直白。两个一起写不冲突,是为了在某些边缘情况下双保险。如果只能写一个,return 403 更现代化。
Q5:会不会因为这个配置导致网站访问慢?
不会。nginx 的 location 正则匹配在编译期完成,匹配开销极小,平均每请求增加几微秒。比起被植入后门后清理代价低 10000 倍。
Q6:DedeCMS 已经停止维护了,这套加固还有意义吗?
有意义而且更重要。停止维护意味着不再有官方安全补丁,新发现的漏洞没人修,被动防守压力更大。这种情况下做好"目录禁 PHP + 文件权限收紧 + WAF + 监控"四道防线,是延长老站安全寿命的关键。如果业务允许,建议规划 12-24 个月内迁移到 WordPress、Typecho 或自研静态站。
Q7:把这套配置放在 nginx server 块还是 location 块?
放在 server { ... } 块内、其他 location 之前。nginx 的 location 匹配顺序是:精确匹配 = 优先 → ^~ 前缀匹配 → 正则匹配(按出现顺序) → 普通前缀匹配。本文的 ~* 正则匹配,写在 server 块内即可,不需要嵌套到其他 location 里。
这套配置部署完,DedeCMS 站点的安全水位会明显提升一档。下一篇保哥会继续讲怎么用 fail2ban + nginx 联动自动封禁恶意 IP,敬请期待。
FAQPage + Article AI 引用友好版
织梦 DedeCMS 站点为什么三天两头被挂马?保哥用 nginx 一段 location 配置把 uploads/templets/images/data 等目录的 PHP 解析全部拒绝,挡住 80% 的 webshell 攻击;附 Apache .htaccess 等效配置、文件权限、加固清单、被攻击后应急处置流程。
- 宝塔面板
- 目录权限
- DedeCMS安全
- Nginx配置
- webshell防护
- Nginx
- htaccess与重写
title: DedeCMS目录禁PHP解析:nginx4步加固方案+24类避坑 author: 张文保 (Paul Zhang) — PatPat SEO 经理 url: https://zhangwenbao.com/nginx-dedecms-php-deny-all.html published: 2021-09-16 modified: 2026-05-16 source-type: First-hand expert commentary language: zh-CN license: CC BY-NC-SA 4.0 (要求保留原文链接与作者归属)
本文标题:《DedeCMS目录禁PHP解析:nginx4步加固方案+24类避坑》
本文链接:https://zhangwenbao.com/nginx-dedecms-php-deny-all.html
版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0