1、如果有以下文件先删除文件


2、然后给nginx里面加上以下代码,放在server {}内,一定要放在 location ~ \.php$之前
location ~* ^/public/uploads/attach/.*\.(php|php5|phtml|phar)$ {
return 403;
}3、重启nginx
4、修改文件
crmeb\app\services\system\attachment\SystemAttachmentServices.php 将 public function upload 方法替换成以下内容
public function upload(int $pid, string $file, int $upload_type, int $type, $menuName, $uploadToken = '')
{
try {
if ($upload_type == 0) {
$upload_type = sys_config('upload_type', 1);
}
$path = make_path('attach', 2, true);
if ($path === '') {
throw new AdminException('无法创建文件夹,请检查您的上传目录权限');
}
$upload = UploadService::init($upload_type);
$res = $upload->to($path)->validate()->move($file, false);
if ($res === false) {
throw new UploadException($upload->getError());
}
$fileInfo = $upload->getUploadInfo();
$extension = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
$denyExt = [
'php','php3','php4','php5','phtml','phar',
'sh','jsp','asp','aspx','exe','bat','cmd','pl','py'
];
if (in_array($extension, $denyExt)) {
@unlink($res->filePath);
throw new UploadException('禁止上传可执行文件');
}
$mime = $fileInfo['type'] ?? '';
$denyMime = [
'application/x-php',
'text/x-php',
'application/x-httpd-php',
];
if (in_array($mime, $denyMime)) {
@unlink($res->filePath);
throw new UploadException('非法文件类型');
}
$allowExt = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'xlsx', 'xls', 'zip', 'mp4'];
if ($fileInfo && $type == 0 && in_array($extension, $allowExt)) {
$data = [
'name' => $fileInfo['name'],
'real_name' => $fileInfo['real_name'],
'att_dir' => $fileInfo['dir'],
'satt_dir' => $fileInfo['thumb_path'],
'att_size' => $fileInfo['size'],
'att_type' => $fileInfo['type'],
'image_type' => $upload_type,
'module_type' => 1,
'time' => $fileInfo['time'] ?? time(),
'pid' => $pid,
'scan_token' => $uploadToken,
];
$this->dao->save($data);
}
return $res->filePath;
} catch (\Throwable $e) {
\think\facade\Log::error('文件上传异常:' . $e->getMessage());
throw new UploadException($e->getMessage());
}
}5、文件地址:\crmeb\crmeb\services\upload\BaseUpload.php
把 checkFileContent 方法改成下面内容:
public function checkFileContent($fileHandle)
{
// 获取文件扩展名
$extension = strtolower(pathinfo($fileHandle->getOriginalName(), PATHINFO_EXTENSION));
$safeBinaryExt = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'zip', 'rar', '7z', 'mp4', 'avi', 'mov', 'mp3', 'wav', 'xlsx', 'xls', 'docx', 'doc', 'pdf'];
if (in_array($extension, $safeBinaryExt)) {
return true;
}
// 只对文本/代码类文件做内容检测
$stream = fopen($fileHandle->getPathname(), 'r');
$content = (fread($stream, filesize($fileHandle->getPathname())));
if (is_resource($stream)) {
fclose($stream);
}
// 检测 PHP 代码标签
if (preg_match('/<\?php|<\?=|<\?[\s]/i', $content)) {
return $this->setError('文件内容包含非法代码');
}
// 检测危险函数调用
if (preg_match('/\beval\s*\(|\bsystem\s*\(|\bexec\s*\(|\bshell_exec\s*\(|\bpassthru\s*\(|\bassert\s*\(|\bcreate_function\s*\(|\bpopen\s*\(|\bproc_open\s*\(|\bpcntl_exec\s*\(/i', $content)) {
return $this->setError('文件内容包含非法代码');
}
// 检测框架敏感关键词
if (preg_match('/\bthink\b|\bphar\b|\bSocket\b|\bChannel\b|\bFlysystem\b|\bPsr6Cache\b|\bCached\b|\bRequest\b|\bdebug\b|\bPsr6Cachepool\b/i', $content)) {
return $this->setError('文件内容不合法');
}
return true;
}6、文件地址:\crmeb\crmeb\services\upload\storage\Local.php
在 Local.php 的 move 方法中,图片上传后加上:

// 如果是图片,验证是否为真实图片
$extension = strtolower(pathinfo($fileHandle->getOriginalName(), PATHINFO_EXTENSION));
if (in_array($extension, ['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
$imageInfo = @getimagesize($fileHandle->getPathname());
if (!$imageInfo) {
return $this->setError('不是合法的图片文件');
}
}完整附件如下:

