织梦禁止上传php文件设置

上传 PHP 文件是织梦站点被植入 webshell 的最直接途径。一旦攻击者成功上传 .php 文件到 uploads 目录并访问执行,就等同于拿到服务器命令执行权限。彻底禁止上传 PHP 文件,需要从代码层白名单、MIME 校验、服务器层执行禁用三个维度同时加固,缺一不可。

一、PHP 文件上传的危害

  • 上传 shell.php 后访问 /uploads/shell.php 即可获得 webshell;
  • 绕过技巧多:双扩展名 shell.php.jpg、大小写 shell.PHP.phtml.phar
  • 配合 .htaccess 可让任意扩展名被当作 PHP 解析;
  • webshell 一旦执行,可读写所有文件、连接数据库、提权控制服务器。

二、织梦默认上传机制

织梦上传校验位于 /include/uploadsafe.class.php/include/dialog/select_media.php/include/dialog/select_images.php。默认配置存在以下问题:

  • 允许的扩展名包含 phtmlphar
  • 仅校验扩展名,不校验 MIME;
  • 部分老版本对大小写、双扩展名处理不严。

三、代码层加固:严格白名单

编辑 /include/uploadsafe.class.php,把允许类型改为严格白名单:

// 仅允许图片与文档
$this->allowTypes=array(
    'jpg','jpeg','gif','png','bmp','webp','ico',
    'pdf','doc','docx','xls','xlsx','ppt','pptx',
    'zip','rar','7z','tar','gz',
    'mp4','mp3','wav','ogg',
    'txt','csv','md'
);

// 显式禁止的可执行扩展名
$forbidden=array(
    'php','php5','php7','php8','phtml','phar',
    'asp','aspx','jsp','jspx',
    'cgi','pl','py','sh','exe','bat','cmd',
    'htaccess','htpasswd','ini','conf','user.ini'
);

$ext=strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if(in_array($ext, $forbidden)){
    exit('禁止上传可执行文件');
}
if(!in_array($ext, $this->allowTypes)){
    exit('文件类型不在允许范围');
}

处理双扩展名

// 检测文件名中是否包含多个 .
$parts=explode('.', $filename);
if(count($parts) > 2){
    // 检查除最后一个外的所有扩展名
    for($i=1; $i < count($parts) - 1; $i++){
        if(in_array(strtolower($parts[$i]), $forbidden)){
            exit('文件名包含可执行扩展名');
        }
    }
}

四、MIME 一致性校验

扩展名校验可能被绕过,必须配合 MIME 检查:

$finfo=finfo_open(FILEINFO_MIME_TYPE);
$mime=finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);

$ext_mime_map=array(
    'jpg'=> ['image/jpeg','image/pjpeg'],
    'png'=> ['image/png'],
    'gif'=> ['image/gif'],
    'pdf'=> ['application/pdf'],
    'zip'=> ['application/zip','application/x-zip-compressed']
);

if(!isset($ext_mime_map[$ext]) || !in_array($mime, $ext_mime_map[$ext])){
    exit('文件扩展名与内容不匹配');
}
MIME 校验只能防御低级攻击,攻击者可通过修改文件头绕过。仍需服务器层执行禁用作为最终防线。

五、服务器层:uploads 禁止执行 PHP

1. Nginx

# 完全禁止 uploads 目录执行 PHP
location ~* /uploads/.*\.(php|php5|php7|phtml|phar)$ {
    deny all;
    return 404;
}

# 禁止 .htaccess 上传后被使用
location ~* /uploads/.*\.ht(access|passwd)$ {
    deny all;
    return 404;
}

# 禁止 user.ini(PHP 用户级配置)
location ~* /uploads/.*\.user\.ini$ {
    deny all;
    return 404;
}

2. Apache

在 uploads 目录放置 .htaccess

# /uploads/.htaccess
<FilesMatch "\.(php|php5|phtml|phar|cgi|pl|py)$">
    Require all denied
</FilesMatch>

# 禁止 PHP 解析
php_flag engine off
RemoveHandler .php .phtml .php3 .php4 .php5

3. PHP-FPM 配置

在 PHP-FPM pool 配置中限制 open_basedir,让 uploads 目录外的 PHP 无法访问核心文件:

; /etc/php-fpm.d/www.conf
php_admin_value[open_basedir]=/www/wwwroot/dede:/tmp

六、关闭不必要上传入口

织梦有多个上传通道,按需保留:

  • 编辑器上传(必要):保留;
  • 会员中心上传(如不需要会员功能):删除 /member/uploads.php
  • 后台文件管理器(/dede/file_manage_view.php):建议删除或禁用;
  • /plus/upload.php:删除。

七、验证拦截效果

  1. 尝试上传 shell.php,应被拒绝;
  2. 尝试上传 shell.php.jpg,应被拒绝;
  3. 尝试上传 shell.PHP,应被拒绝;
  4. shell.php 改名为 shell.jpg 上传,再尝试访问 /uploads/shell.jpg.php,应 404;
  5. 用 burpsuite 抓包修改 MIME,应仍被扩展名校验拦截。

八、后门排查

设置完成后,扫描 uploads 目录是否已存在历史 PHP 文件:

find /www/wwwroot/dede/uploads -name "*.php" -o -name "*.phtml" -o -name "*.phar"
find /www/wwwroot/dede/uploads -name ".htaccess"
find /www/wwwroot/dede/uploads -name ".user.ini"

发现任何匹配立即删除并查清来源。

九、注意事项

  • Nginx 配置修改后用 nginx -t 校验,避免语法错误导致全站 502;
  • Apache .htaccess 必须放在 uploads 根目录才生效;
  • 第三方编辑器可能自带上传逻辑,需单独加固;
  • CDN 缓存可能让旧的可执行文件仍可访问,配置后清缓存。
禁止上传 PHP 文件是织梦防 webshell 的核心措施,建议把"代码白名单 + MIME 校验 + nginx 执行禁用 + 后门扫描"四件事一次性配齐。三层防御互为补充,即便某一层被绕过,仍有其他层兜底。配置完成后定期用 sqlmap、xray 等工具复测上传通道,确保防护持续有效。