本文目录导读:

针对“上传目录的权限限制”,核心目标通常是:允许 Web 服务器写入(上传文件),但禁止执行(防止上传木马、脚本被解析)。
以下是针对不同服务器环境(Linux/Nginx/Apache/Windows)的详细配置方案:
Linux 系统(最推荐,核心逻辑)
假设你的上传目录是 /var/www/html/uploads。
文件系统权限(基础)
确保 Web 用户(如 www-data 或 nginx)可以写入,但禁止“所有者”和“其他用户”的执行权限。
# 假设 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(执行)权限,可以通过 umask 或 chmod 在上传后统一去除。
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;
}
高安全环境(文件存储分离)
如果对安全要求极高(如社交平台、云盘):
- 存储目录在 Web 根目录之外(
/data/uploads/,而不是/var/www/html/uploads/)。 - 通过一个专门的 PHP/Python 脚本来“分发”文件(如
getfile.php?name=xxx.jpg),在该脚本中限制只能读取文件内容,不能执行。 - 使用 CDN 或对象存储(如阿里云 OSS、AWS S3),上传后直接返回 CDN URL,本地服务器不存储文件,或只存临时目录。
最佳实践清单
| 层数 | 操作 | 说明 |
|---|---|---|
| 1 | 白名单扩展名 | 只允许 jpg, png, gif, pdf 等上传。 |
| 2 | 重新命名文件 | 使用时间戳+随机字符串,避免恶意文件名。 |
| 3 | 检查 MIME 类型 | 使用 finfo 或 getimagesize 等检测真实文件头。 |
| 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.txt 或 shell.php 来验证访问是否被阻止。