
Model::unguard()会全局禁用Eloquent的批量赋值保护机制,导致所有字段均可被用户输入直接写入数据库,极易引发越权修改、数据污染甚至业务逻辑绕过,与SQL注入无关但危害同样严重。
`model::unguard()`会全局禁用eloquent的批量赋值保护机制,导致所有字段均可被用户输入直接写入数据库,极易引发越权修改、数据污染甚至业务逻辑绕过,**与sql注入无关但危害同样严重**。
在Laravel中,Model::unguard()是一个高危操作——它并非SQL注入防护手段,而是对Eloquent核心安全机制的主动关闭。其作用是临时(或永久)禁用模型的“批量赋值保护”(Mass Assignment Protection),使得$model->fill($request->all())、Model::create()、Model::updateOrCreate()等方法不再受$fillable白名单约束,任何请求参数(包括攻击者伪造的is_admin=1、status='deleted'、balance=999999)都将无条件写入数据库。
⚠️ 本质区别需厘清:
-
SQL注入:发生在SQL语句构造阶段,攻击者通过恶意输入篡改查询逻辑(如
' OR 1=1 --)。Laravel默认通过参数绑定已有效防御,unguard()对此无影响也无关联。 -
批量赋值漏洞:发生在数据持久化前的属性映射阶段,属于业务逻辑层越权。即使SQL完全安全,错误的数据也能被写入——例如将普通用户提交的
role_id=1(管理员ID)直接存入users表,从而提权。
✅ 安全实践(必须遵守):
-
永远显式定义
$fillable:仅列出允许前端提交的字段,如protected $fillable = ['name', 'email', 'avatar_url'];
-
禁用
$guarded = []:该配置等价于“允许所有字段”,与unguard()效果相同,属严重反模式; -
慎用
unguard():仅在极少数可信上下文(如后台管理脚本、种子数据填充)中临时启用,并立即调用Model::reguard()恢复保护:User::unguard(); User::create(['name' => 'Admin', 'is_admin' => true]); // 仅在此处绕过 User::reguard(); // 立即恢复!
-
结合验证层加固:在控制器中使用Form Request验证,对关键字段做业务规则校验(如
email格式、status枚举值),不依赖模型层兜底。
? 典型攻击场景示例:
假设用户注册接口代码为:
// 危险!未定义$fillable且调用了unguard()
User::unguard();
User::create($request->all()); // 攻击者提交:{"name":"hacker","email":"x@x.com","is_admin":1}
结果:新用户被创建且is_admin=1直接入库,攻击者获得管理员权限——这不是SQL被篡改,而是业务权限被劫持。
? 总结:Model::unguard()本身不引入SQL注入风险,但它彻底瓦解了Laravel最重要的业务安全防线之一。在生产环境中,应将其视为“禁止项”,坚持$fillable白名单原则,并通过分层验证(请求验证 → 模型填充 → 业务逻辑检查)构建纵深防御体系。安全不是“少写一行代码”,而是“多守一道关”。











