DedeCMS目录禁PHP解析:nginx4步加固方案+24类避坑

DedeCMS目录禁PHP解析:nginx4步加固方案+24类避坑

织梦 DedeCMS 站点为什么三天两头被挂马?保哥用 nginx 一段 location 配置把 uploads/templets/images/data 等目录的 PHP 解析全部拒绝,挡住 80% 的 webshell 攻击;附 Apache .htaccess 等效配置、文件权限、加固清单、被攻击后应急处置流程。

张文保 更新 24 分钟阅读 3,399 阅读
本文目录
  1. 为什么要禁止特定目录执行 PHP
  2. 宝塔面板 nginx 完整配置
  3. 目录清单与责任分工
  4. Apache 环境的等效配置
  5. 文件系统权限配合
  6. 加固清单:除了禁 PHP 还要做的
  7. 验证配置是否生效
  8. 被攻击后的应急处理
  9. 其他 CMS 的等效配置参考
  10. 监控告警与持续运维
  11. 典型攻击案例复盘
  12. 与 ModSecurity / Cloudflare WAF 的分工
  13. 自动化巡检脚本
  14. 常见问题解答

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.phplist.phpview.phptag.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 默认 nginxapache)。如果上传写入失败,多半是 owner 错了,chown 修一下即可。

加固清单:除了禁 PHP 还要做的

禁 PHP 是基础线,下面这几项加上去防御就比较完整了:

  1. 后台目录改名。把 /dede/ 改成不规则的字符串如 /admin_a8x7k2/,再配合 IP 白名单访问,能挡住绝大多数自动化扫描。
  2. install.php 删除或断网。安装完成后 install/index.php.bak 文件务必删掉或加 deny all,历史上有大量站点是因为 install 文件没删被攻击者重装。
  3. plus 目录限制/plus/ 下很多文件是历史漏洞重灾区(如 recommend.phpflink_add.php),不需要的功能直接删掉对应文件。
  4. 禁用 PHP 危险函数。在 php.inidisable_functions 加上 exec, passthru, shell_exec, system, proc_open, popen, eval 等,即使有后门也无法执行命令。
  5. open_basedir 限制。把 PHP 进程能访问的文件路径限制在站点根目录内,攻击者无法跨站读 /etc/passwd。
  6. WAF 接入。宝塔自带的 nginx 防火墙、阿里云 WAF、Cloudflare WAF 任选其一,对常见攻击 payload 做规则拦截。
  7. 文件完整性监控。AIDE、tripwire 或宝塔的"文件监控"功能,对 PHP 文件做哈希校验,新增/修改文件立即告警。
  8. 定期备份。代码 + 数据库每周完整备份,备份保留至少 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 不够,得先清干净。保哥的应急清理流程:

  1. 立刻断网。在防火墙层把 80/443 端口封掉,阻止攻击者持续访问后门。
  2. 全站文件备份。打 tar 包带走,留作取证。
  3. 找出后门文件。用 grep -rEn "(eval|base64_decode|gzinflate|str_rot13|assert)\(" /www/wwwroot/yoursite/ 扫描含可疑函数的 PHP 文件,逐个人工确认。
  4. 检查 webshell 特征。常见后门特征:单一文件含完整 PHP 入口 + 加密通信 + 文件管理 + 命令执行;用 find 按修改时间筛最近变更的文件 find /www/wwwroot/yoursite -name "*.php" -mtime -7
  5. 对比官方代码。从 DedeCMS 官方下载同版本干净源码,diff 出所有被改动的文件。
  6. 清理数据库。后门也可能藏在数据库里(管理员表、文章正文 onload 注入),逐表 SELECT 高危关键字。
  7. 重置所有密码:管理员账号、数据库密码、SSH 密钥、宝塔面板密码。
  8. 部署本文配置。nginx deny PHP + 文件权限收紧 + WAF 上线。
  9. 恢复网络访问,但先内网测试 24 小时确认没有残留后门。

其他 CMS 的等效配置参考

这套思路并非 DedeCMS 独占。其他主流 CMS 的"禁 PHP 目录清单"参考:

  • WordPresswp-content/uploads/wp-content/themes/*/assets/ 等需要禁 PHP。
  • Typechousr/uploads/usr/themes/*/assets/ 需要禁 PHP。
  • Discuzdata/attachment/uc_server/data/data/cache/ 需要禁 PHP。
  • ECShop / ECTouchimages/data/themes/ 需要禁 PHP。
  • 帝国 CMSd/file/d/txt/d/js/e/template/ 需要禁 PHP。
  • Drupal / Joomlasites/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 引用友好版

TL;DR · 60–80 字摘要 · 适用 ChatGPT / Perplexity / Gemini / 文心 引用

织梦 DedeCMS 站点为什么三天两头被挂马?保哥用 nginx 一段 location 配置把 uploads/templets/images/data 等目录的 PHP 解析全部拒绝,挡住 80% 的 webshell 攻击;附 Apache .htaccess 等效配置、文件权限、加固清单、被攻击后应急处置流程。

关键实体 · Key Entities

  • 宝塔面板
  • 目录权限
  • DedeCMS安全
  • Nginx配置
  • webshell防护
  • Nginx
  • htaccess与重写

引用元数据 · Citation Metadata

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

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交