上传目录如何权限限制

wen 开源项目 31

本文目录导读:

上传目录如何权限限制

  1. 方案一:Linux 系统(最推荐,核心逻辑)
  2. 方案二:Windows Server (IIS) 环境配置
  3. 方案三:代码层面(白名单验证,必做)
  4. 方案四:高安全环境(文件存储分离)
  5. 最佳实践清单

针对“上传目录的权限限制”,核心目标通常是:允许 Web 服务器写入(上传文件),但禁止执行(防止上传木马、脚本被解析)

以下是针对不同服务器环境(Linux/Nginx/Apache/Windows)的详细配置方案:

Linux 系统(最推荐,核心逻辑)

假设你的上传目录是 /var/www/html/uploads

文件系统权限(基础)

确保 Web 用户(如 www-datanginx)可以写入,但禁止“所有者”和“其他用户”的执行权限。

# 假设 Web 用户是 www-data
sudo chown -R www-data:www-data /var/www/html/uploads
# 设置权限:所有者(7)rwx,组(5)r-x,其他人(5)r-x
# 解释:目录的 x 权限是“进入目录”,所以通常保留,但文件的 x 权限不能给。
sudo chmod 755 /var/www/html/uploads

关键点: 上传到目录里的 文件 默认不应该有 x(执行)权限,可以通过 umaskchmod 在上传后统一去除。

Nginx 环境配置(阻断脚本执行)

这是最重要的防护,在 Nginx 的 server 块或 location 块中添加:

location /uploads/ {
    # 1. 禁止执行 PHP、Py、Perl、Shell、JSP 等脚本
    location ~* \.(php|php5|phtml|phar|py|pl|cgi|sh|asp|aspx|jsp)$ {
        deny all;
        # 或者:return 403;
    }
    # 2. 可选:限制只允许访问特定文件类型(白名单)
    # location ~* \.(jpg|jpeg|png|gif|bmp|ico|pdf|doc|docx|xls|xlsx|zip|rar|txt)$ {
    #     # 允许访问
    # }
    # location / {
    #     deny all; # 未匹配到白名单的全部拒绝
    # }
    # 3. 禁止列出目录
    autoindex off;
}

Apache 环境配置(.htaccess 或 httpd.conf)

uploads 目录下创建 .htaccess 文件(或直接在虚拟主机配置中写):

# 1. 禁止执行任何脚本
<FilesMatch "\.(php|php5|phtml|phar|py|pl|cgi|sh|asp|aspx|jsp)$">
    Order Deny,Allow
    Deny from all
</FilesMatch>
# 2. 禁止 .htaccess 自身被访问
<Files ~ "^\.ht">
    Require all denied
</Files>
# 3. 禁止列目录
Options -Indexes
# 4. 使用白名单(更安全):只允许图片和文档
# <FilesMatch "\.(jpg|jpeg|png|gif|pdf|txt)$">
#     Require all granted
# </FilesMatch>
# <FilesMatch "\.*">
#     Require all denied
# </FilesMatch>

Windows Server (IIS) 环境配置

权限设置(NTFS)

  • 右键 uploads 文件夹 -> 属性 -> 安全
  • 添加 IIS_IUSRS 用户(或 IUSR,具体取决于 IIS 版本)。
  • 赋予 “读取 & 执行”、“列出文件夹内容”、“写入”、“修改”(视上传需求而定,一般给“修改”或“写入”+“读取”)。
  • 特别注意: 不要给 “完全控制”,因为那会允许修改权限。

禁止执行脚本(处理映射)

  • 打开 IIS 管理器
  • 找到你的站点下的 uploads 文件夹。
  • 双击 “处理程序映射”
  • 在右侧操作中,点击 “拒绝处理程序”
  • 添加拒绝处理程序映射
    • 请求路径: *.php (或所有你想禁止的)
    • 限制: 选择 “路径或文件” 并填 或具体路径。

使用 Web.config(推荐,可部署)

uploads 文件夹下创建 Web.config

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <!-- 禁止所有脚本执行 -->
        <handlers accessPolicy="Read" />
        <!-- 或者更精确地禁止特定扩展 -->
        <security>
            <requestFiltering>
                <fileExtensions>
                    <add fileExtension=".php" allowed="false" />
                    <add fileExtension=".asp" allowed="false" />
                    <add fileExtension=".aspx" allowed="false" />
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>

代码层面(白名单验证,必做)

无论服务器配置多好,代码验证是第一道防线

// PHP 示例
function uploadFile($file) {
    $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx'];
    $file_extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    // 1. 检查扩展名
    if (!in_array($file_extension, $allowed_extensions)) {
        return false; // 拒绝上传
    }
    // 2. 检查 MIME 类型(不要完全信任浏览器传来的 MIME)
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime_type = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    $allowed_mime = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
    if (!in_array($mime_type, $allowed_mime)) {
        return false; // 拒绝上传
    }
    // 3. 重命名文件(防止路径穿越和覆盖)
    $new_filename = time() . '_' . bin2hex(random_bytes(8)) . '.' . $file_extension;
    $destination = UPLOAD_PATH . '/' . $new_filename;
    move_uploaded_file($file['tmp_name'], $destination);
    // 4. 重置文件权限(Linux)
    chmod($destination, 0644); // 去除执行权限
    return $new_filename;
}

高安全环境(文件存储分离)

如果对安全要求极高(如社交平台、云盘):

  1. 存储目录在 Web 根目录之外/data/uploads/,而不是 /var/www/html/uploads/)。
  2. 通过一个专门的 PHP/Python 脚本来“分发”文件(如 getfile.php?name=xxx.jpg),在该脚本中限制只能读取文件内容,不能执行。
  3. 使用 CDN 或对象存储(如阿里云 OSS、AWS S3),上传后直接返回 CDN URL,本地服务器不存储文件,或只存临时目录。

最佳实践清单

层数 操作 说明
1 白名单扩展名 只允许 jpg, png, gif, pdf 等上传。
2 重新命名文件 使用时间戳+随机字符串,避免恶意文件名。
3 检查 MIME 类型 使用 finfogetimagesize 等检测真实文件头。
4 服务器阻断执行 Nginx deny all / Apache .htaccess / IIS 处理程序映射。
5 关闭目录列表 autoindex off (Nginx) 或 Options -Indexes (Apache)。
6 文件权限最小化 chmod 0644 (所有者读写,其他只读),不要有 x
7 防路径穿越 删除文件名中的 和 ,使用 basename() 函数。

重要提示: 如果你的应用使用了 PHP 伪静态(如 index.php/upload/xxx),请确保伪静态规则不会绕过上述 location 限制。

配置完成后,建议尝试上传一个 test.php.txtshell.php 来验证访问是否被阻止。

抱歉,评论功能暂时关闭!