upload_max_filesize 应按业务实际设为最小必要值(如2M),post_max_size 必须≥前者且略大(如4M),严禁设0或过大;二者需与 client_max_body_size、open_basedir、disable_functions 等协同配置,并严格限制上传目录执行权限与临时目录安全。

upload_max_filesize 和 post_max_size 怎么设才安全
这两个参数直接决定单个请求能上传多大文件,设太高等于给攻击者留后门。默认值(比如 2M / 8M)对大多数业务都偏大,尤其当你的应用不处理图片、视频等大文件时。
建议按实际需求设死上限,例如仅允许上传头像或表单附件:把 upload_max_filesize 设为 2M,post_max_size 设为略大一点的 4M(必须 ≥ upload_max_filesize,否则上传直接失败)。
- 别用
0或极大值(如1G),这会让恶意构造的超大 POST 请求耗尽内存或磁盘 - 修改后必须重启 PHP-FPM 或 Apache,
phpinfo()页面里确认生效 - 注意 Nginx 用户还要同步调大
client_max_body_size,否则请求在 Web 层就被拒了
如何禁用危险的文件上传执行权限
上传目录如果被 Apache/Nginx 直接映射为可访问路径(如 /var/www/html/uploads/),而里面又没做隔离,攻击者上传 shell.php 后就能直接执行——这是最常见 RCE 入口。
核心原则:上传目录绝不允许 PHP 解析。Nginx 下用 location ~ ^/uploads/.*\.php$ { deny all; };Apache 下在对应目录加 <files> Require all denied</files>。
立即学习“PHP免费学习笔记(深入)”;
- 更稳妥的做法是把上传目录放在 Web 根目录外(如
/var/www/uploads/),PHP 脚本用readfile()或fpassthru()输出,不走 Web 服务器直链 - 上传后立即重命名(用 hash+扩展名白名单校验),别保留原始文件名
- 别依赖前端 JS 校验,后端必须用
getimagesize()、finfo_file()等验证真实 MIME 类型
open_basedir 和 disable_functions 对上传场景的作用
open_basedir 不是上传专用,但它能限制上传脚本能读写的范围。设成 /var/www/html/:/tmp/ 后,即使上传了恶意脚本,它也读不到 /etc/passwd 或其他项目目录。
disable_functions 要重点关掉 exec、system、shell_exec、passthru ——这些函数常被上传的 Webshell 用来执行系统命令。注意:move_uploaded_file() 必须保留,否则上传流程直接中断。
-
open_basedir值末尾的冒号不能漏,否则会变成“仅允许访问该目录”,连临时文件目录都写不了 -
disable_functions修改后,用php -r "print_r(function_exists('exec'));"快速验证是否生效 - 别禁用
file_put_contents或fopen,否则日志、缓存、上传保存都会失败
为什么 upload_tmp_dir 必须显式配置且权限收紧
PHP 默认用系统临时目录(如 /tmp),所有用户进程都能往里写,上传的临时文件可能被同服务器其他账户窥探或篡改。更糟的是,如果攻击者能预测临时文件名(如 phpXXXXXX),甚至能提前创建符号链接劫持写入目标。
解决方案:在 php.ini 里指定独立目录,比如 upload_tmp_dir = /var/tmp/php-uploads,然后 chown root:www-data + chmod 750,确保只有 Web 服务组可读写。
- 该目录不能和 Web 可访问路径混用,也不能设成
/var/www/下任何子目录 - 检查 SELinux 或 AppArmor 是否阻止 PHP 写入新路径,CentOS/RHEL 上常用
setsebool -P httpd_read_user_content 1 - 如果用 PHP-FPM,还需确认
www.conf里的php_admin_value[upload_tmp_dir]没有覆盖你设的值



















