真正守住php文件安全的关键在于严格控制include、file_get_contents、move_uploaded_file等函数的路径与内容可信度:禁用allow_url_include,对include参数强制白名单校验;$_files验证必须用finfo_open检测真实mime类型而非伪造的type字段;上传文件须重命名、存于web根目录外、禁用脚本执行权限,并在解析csv/xml/json前做内容级防护。

PHP文件安全不是靠“学完一套理论”就能落地的,关键在识别哪些操作会直接暴露服务器、哪些验证看似有效实则形同虚设。真正要守住的,是 include、file_get_contents、move_uploaded_file 这几个函数背后的真实路径控制和内容可信度。
怎么防 include 被绕成本地文件包含(LFI)
问题不在于用不用 include,而在于传给它的参数是否可控、是否经过白名单校验。很多代码写成 include($_GET['page'] . '.php'),攻击者加个 %00 或 ../etc/passwd 就能读系统文件。
- 绝对禁止拼接用户输入进
include/require的路径中 - 必须用白名单:比如只允许
['home', 'about', 'contact'],再用in_array()判定,别做字符串匹配或正则“过滤” - 如果真要动态加载,优先用
__DIR__ . '/templates/' . $safe_file . '.php'这种硬编码根路径 + 白名单组合,避免realpath()后仍被绕过 - 确认
allow_url_include在php.ini中为Off,否则php://filter或data://伪协议可能直接执行代码
$_FILES 验证为什么不能只看 $_FILES['file']['type']
$_FILES['file']['type'] 是浏览器发来的字段,完全可伪造;扩展名也能被改;仅靠这两项拦不住一句话木马伪装成 avatar.jpg。
- 必须用
finfo_open(FILEINFO_MIME_TYPE)检查真实 MIME 类型,例如image/jpeg,且只接受明确列出的类型 - 对图片类文件,可额外调用
getimagesize(),它读取文件头,失败即说明不是合法图像 - 不要用
pathinfo($filename, PATHINFO_EXTENSION)做判断——攻击者传shell.php.jpg,你取到的是jpg,但 Web 服务器可能按最后后缀解析 - 上传后立刻重命名,用
sha256_file($tmp_name) . '.png'或random_bytes(16)生成名字,彻底切断原始文件名影响
上传文件存哪才不算“放门口”
存在 /var/www/html/uploads/ 就等于把钥匙挂门把手上。只要上传成功,攻击者就能用 URL 直接访问并执行 PHP 文件(如果服务器配置不当)。
- 存储路径必须脱离 Web 根目录,比如
/var/www/private_uploads/,确保 Web 服务器对该目录无Location或Alias映射 - 该目录权限设为
750,属主为 PHP 运行用户(如www-data),组可读,其他人无任何权限 - 如果必须提供下载,走 PHP 脚本中转:
readfile()+header('Content-Disposition: attachment'),而不是让用户直连文件 URL - 禁用该目录下所有脚本执行能力——Nginx 加
location ~ \.php$ { deny all; },Apache 用php_flag engine off
为什么 move_uploaded_file() 之后还要检查文件内容
这个函数只保证文件从临时目录搬过去了,不保证它没被注入恶意 payload。尤其当业务需要解析上传的 CSV、XML、JSON 时,文件内容本身就成了攻击面。
- CSV 解析别用
fgetcsv()直读,先用str_starts_with(file_get_contents($tmp), "\xEF\xBB\xBF")排除 BOM 注入,再限制字段数和单字段长度 - XML 解析前必须禁用外部实体(
libxml_disable_entity_loader(true)),否则xxe攻击可读取服务器文件 - JSON 解析用
json_decode($input, flags: JSON_THROW_ON_ERROR),并检查返回值是否为array或object,防止null或布尔值被误用 - 所有文件读取操作,都应配合
is_uploaded_file()再次确认来源,防止攻击者伪造$_FILES数组绕过上传流程
最易被忽略的一点:安全不是某个函数调用的堆砌,而是整个数据流里每个环节的信任边界是否清晰。比如你用 finfo 验了 MIME,却把文件名原样存进数据库、再在前端用 echo $row['filename'] 输出——这就又开了 XSS 口子。每一步输出、每一步包含、每一次读取,都要问一句:这数据此刻是否还可信?
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











