防止file_put_contents()写入webshell的关键是切断攻击链:严格校验路径(realpath+白名单)、固定安全扩展名、内容结构过滤(php特征扫描)、权限隔离(禁执行权限+web服务器配置)及行为监控。

防止 file_put_contents() 被用于写入 WebShell(俗称“写马”),关键不是禁用函数,而是切断攻击链:堵住恶意输入来源、限制写入路径、过滤内容结构、控制文件权限。单纯依赖黑名单或简单正则极易被绕过。
严格校验目标文件路径
攻击者常利用路径遍历(如 ../../shell.php)把木马写到网站可访问目录。必须做两件事:
- 用
realpath($target)获取绝对路径,并检查是否落在白名单目录内(如仅允许写入/var/www/uploads/) - 若
realpath()返回false(路径不存在、不可访问或含非法符号),直接拒绝写入——这是绕过常见点,不能忽略 - 禁止用户控制扩展名,固定后缀(如只允许
.jpg、.log),不要拼接$_POST['ext']
内容层面做结构过滤
光拦扩展名不够,PHP代码可能藏在图片末尾、日志字段或 JSON 值里。需主动识别可疑语法:
- 对写入内容做基础 PHP 特征扫描:匹配
<?php、eval(、@system(、assert(、create_function(等高危模式 - 避免只用
preg_match('/', $data)这类简单判断——攻击者可用='xxx'?>或 Base64 编码绕过 - 更稳妥做法:若业务允许,统一转义输出(如 HTML 实体化)、或强制重编码为二进制格式(如图片写入前验证 PNG 头)
运行时权限与上下文隔离
即使写入成功,也要让木马无法执行:
- Web 服务器用户(如 www-data)对上传/缓存目录**取消执行权限**:
chmod -x /var/www/uploads/ - 配置 Web 服务器(Nginx/Apache)禁止解析特定目录下的 PHP:
location ~ ^/uploads/.*\.php$ { return 403; } - 使用独立的、无 PHP 解析能力的子域名托管用户上传内容(如
static.example.com)
写入行为本身加管控
监控和限制异常写入动作:
- 记录每次
file_put_contents()的目标路径、大小、调用栈(可结合 error_log 或审计日志) - 对高频写入(如 1 秒内多次写同一目录)触发告警或临时封禁
- 生产环境避免用
file_put_contents()直接保存用户提交的任意内容;优先走专用存储服务(如对象存储 OSS)或数据库 BLOB 字段











