最核心修复方式是模型中配置$fillable白名单,如protected $fillable = ['username', 'email', 'password', 'nickname'];禁用$guarded=[]、$request->all()等高危写法,敏感字段须服务层校验。

直接在模型中配置 $fillable 数组,只列出允许前端提交的字段,是最核心、最有效的修复方式。
明确声明可批量赋值字段(白名单)
这是 Laravel 官方推荐且最可靠的做法。不要依赖 $guarded,而是主动定义哪些字段可以被 create()、fill()、update() 等方法接收。
- 在用户模型中写:
protected $fillable = ['username', 'email', 'password', 'nickname']; - 像
is_admin、balance、tenant_id这类敏感字段,绝不能出现在$fillable里 - 如果字段名动态变化或业务逻辑复杂,可配合
only()在控制器中二次过滤:User::create($request->only(['username', 'email', 'password']));
避免使用高危写法
很多漏洞就源于一行看似方便的代码。以下写法必须禁止:
-
$user->fill($request->all());—— 全量接收,等于敞开大门 -
User::create($request->all());—— 同样危险,未加任何字段限制 -
protected $guarded = [];—— 空数组表示“所有字段都可赋值”,等同于关闭防护
结合 DTO 或请求验证类做前置过滤
把字段控制从模型层上移到请求处理层,更清晰也更安全:
- 定义一个
RegisterRequest类,重写rules()并在validated()中只取所需字段 - 或新建一个数据传输对象(DTO),用
Arr::only()显式提取字段再传给模型 - 这样即使未来模型字段变更,也不会意外暴露新字段
敏感操作必须服务层校验
白名单只是第一道门,关键字段修改还需业务逻辑兜底:
- 比如管理员权限变更,不能靠前端传
is_admin,而应由后台调用$user->makeAdmin()这类专用方法 - 余额变动、租户切换等操作,必须走独立接口,带鉴权+日志+审批流
- 数据库写入前,可用模型观察者(Observer)做最终拦截:
if (in_array('is_admin', array_keys($attributes))) { throw new UnauthorizedException(); }











