Laravel 默认通过PDO预处理防SQL注入,where()等方法自动绑定参数;需避免字符串拼接和未绑定的whereRaw()/selectRaw();$fillable和$casts不防注入,仅保障数据完整性与类型转换。

用 Eloquent 或 DB::table() 时,参数必须走绑定,别拼字符串
只要不用 whereRaw()、selectRaw() 这类“裸 SQL”接口,Laravel 默认就防 SQL 注入。它的底层用的是 PDO 预处理,所有通过 where()、update()、insert() 传进去的值都会被安全绑定。
常见错误是手痒拼接用户输入:
DB::select("SELECT * FROM users WHERE name = '" . request('name') . "'"); // 危险!
正确做法是交给框架处理:
DB::table('users')->where('name', request('name'))->get()User::where('email', $request->input('email'))->first()- 批量操作也一样安全:
User::whereIn('id', $ids)->delete()($ids是数组)
whereRaw() 和 selectRaw() 是高危区,必须手动绑定参数
这些方法绕过了 Laravel 的自动绑定机制,相当于开了个后门。如果里面混入用户输入又没处理,立刻中招。
错误示范:
User::whereRaw("email LIKE '%{$_GET['q']}%'")->get(); // 直接炸
正确写法只有两种:
- 用问号占位 + 数组传参:
whereRaw("email LIKE ?", ['%' . $q . '%']) - 用命名绑定:
whereRaw("email LIKE :pattern", ['pattern' => '%' . $q . '%']) - 能不用
Raw就别用 —— 比如where('email', 'like', "%{$q}%")更安全也更可读
模型的 $fillable 和 $casts 不防注入,但影响数据完整性
很多人误以为设置 $fillable 就能防注入,其实它只控制哪些字段能被 create() / fill() 批量赋值,和 SQL 构造无关。真正的风险在“把恶意字符串当数字用”这类隐式转换漏洞。
比如用户传 price=100 OR 1=1,而模型里 $casts = ['price' => 'int'],PHP 会把它转成 100,反而拦住了攻击;但如果没 cast,又直接塞进 whereRaw(),就危险了。
-
$casts能帮你做基础类型兜底,但不能替代绑定 -
$fillable是防 mass-assignment 漏洞,不是 SQL 注入防火墙 - 敏感操作(如后台导出、条件统计)务必校验输入类型,别信
request()->all()
第三方包或原生查询里用 PDO::quote() 是下策,优先走 Laravel 绑定
有些老项目或集成遗留代码时,会看到 $pdo->quote($input) 这种写法。它确实能转义单引号,但有局限:不同数据库转义规则不同,且不处理空字节、宽字节等边界情况。
Laravel 的绑定是 PDO 层面的预处理,由驱动保障,比字符串转义可靠得多。
- 除非你完全脱离 Laravel 查询构建器(比如直连
PDO实例),否则别自己 quote - 如果非得写原生 SQL,用
DB::select($sql, $bindings),让框架接管绑定 - 注意:
DB::unprepared()不支持绑定,纯执行语句,传参前必须严格过滤
该防的地方就那几处:别拼 SQL 字符串、Raw 方法必绑参、别迷信模型配置能代替输入控制。剩下都是框架兜着的。真正容易翻车的,往往是那个“就这儿加一行 SQL 应该没问题”的瞬间。











