You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何保护密码保护环境下的CKEditor文件上传PHP脚本免受未授权访问?

保护CKEditor PHP文件上传脚本的关键措施

针对你给出的CKEditor上传脚本,我整理了几个核心的安全加固手段,帮你抵御未授权访问和常见攻击:

  • 严格校验请求来源
    你已经定义了$accepted_origins,但要注意不能只依赖$_SERVER['HTTP_REFERER'](它可以被伪造),不过结合其他验证还是有价值的。可以解析来源的主机名再做对比,避免子域名或伪造的路径绕过:

    if (!empty($_SERVER['HTTP_REFERER'])) {
        $referer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
        if (!in_array($referer_host, $accepted_origins)) {
            $funcNum = intval($_GET['CKEditorFuncNum']);
            echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'Unauthorized origin.');</script>";
            exit;
        }
    } else {
        // 无Referer的请求直接拒绝
        exit('Invalid request');
    }
    
  • 验证CKEditor专属参数
    必须确保CKEditorFuncNum和CKEditor参数合法,防止恶意构造请求:

    if (!isset($_GET['CKEditorFuncNum']) || !is_numeric($_GET['CKEditorFuncNum'])) {
        exit('Invalid request parameters');
    }
    $funcNum = intval($_GET['CKEditorFuncNum']);
    // 可选:验证CKEditor实例名是否符合预期
    if (isset($_GET['CKEditor']) && !preg_match('/^[a-zA-Z0-9_-]+$/', $_GET['CKEditor'])) {
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'Invalid editor instance.');</script>";
        exit;
    }
    
  • 强文件类型与内容校验
    绝不能只靠文件名后缀判断文件类型,要结合MIME类型和文件内容检测:

    // 用finfo检测真实文件类型
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $file_mime = $finfo->file($_FILES['upload']['tmp_name']);
    $allowed_mimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
    if (!in_array($file_mime, $allowed_mimes)) {
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'Only image files are allowed.');</script>";
        exit;
    }
    // 额外验证文件后缀(双重保障)
    $allowed_exts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
    $file_ext = strtolower(pathinfo($_FILES['upload']['name'], PATHINFO_EXTENSION));
    if (!in_array($file_ext, $allowed_exts)) {
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'Invalid file extension.');</script>";
        exit;
    }
    
  • 限制文件大小
    主动设置上传文件的最大限制,避免超大文件耗尽服务器资源:

    $max_size = 2 * 1024 * 1024; // 2MB
    if ($_FILES['upload']['size'] > $max_size) {
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'File size exceeds 2MB limit.');</script>";
        exit;
    }
    
  • 安全处理文件名与路径
    避免使用原始文件名(防止路径遍历和恶意文件名),生成随机安全文件名,同时确保上传路径在预期目录内:

    // 生成随机文件名
    $safe_filename = uniqid('ckupload_') . '.' . $file_ext;
    // 确保上传目录真实存在且安全
    $upload_folder = realpath('../uploads/') . '/';
    if (!$upload_folder || !is_dir($upload_folder) || !is_writable($upload_folder)) {
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'Upload directory unavailable.');</script>";
        exit;
    }
    $upload_path = $upload_folder . $safe_filename;
    // 防止路径遍历攻击,确保最终路径在上传目录内
    if (strpos(realpath($upload_path), $upload_folder) !== 0) {
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'Invalid upload path.');</script>";
        exit;
    }
    
  • 添加CSRF防护
    通过CSRF令牌验证请求合法性,防止跨站请求伪造:
    首先在前端页面生成并传递令牌(假设使用session存储):

    // 页面初始化时生成CSRF令牌
    session_start();
    if (!isset($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    

    修改CKEditor的上传URL:

    CKEDITOR.replace('your_editor_id', {
        filebrowserUploadUrl: '/path/to/upload.php?CKEditorFuncNum={num}&csrf_token=<?php echo $_SESSION['csrf_token']; ?>'
    });
    

    然后在上传脚本中验证:

    session_start();
    if (!isset($_GET['csrf_token']) || $_GET['csrf_token'] !== $_SESSION['csrf_token']) {
        $funcNum = intval($_GET['CKEditorFuncNum'] ?? 0);
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'Unauthorized request.');</script>";
        exit;
    }
    
  • 设置安全的文件权限
    上传目录权限设为755(仅所有者可写),上传后的文件权限设为644(无执行权限):

    if (move_uploaded_file($_FILES['upload']['tmp_name'], $upload_path)) {
        chmod($upload_path, 0644);
        // 返回成功给CKEditor
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '$upload_path', '');</script>";
    } else {
        echo "<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '', 'Failed to upload file.');</script>";
    }
    
  • 记录上传日志
    记录所有上传请求的关键信息(IP、文件名、时间、结果),方便后续排查异常:

    $log_entry = sprintf(
        "%s - IP: %s, File: %s, Result: %s\n",
        date('Y-m-d H:i:s'),
        $_SERVER['REMOTE_ADDR'],
        $_FILES['upload']['name'],
        file_exists($upload_path) ? 'Success' : 'Failed'
    );
    file_put_contents('../upload_logs.txt', $log_entry, FILE_APPEND);
    

内容的提问来源于stack exchange,提问作者leemon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:17:33