laravel默认安全,但whereraw()等raw方法及db::select()拼接用户输入极危险;必须用参数绑定或白名单校验动态字段,orm安全不等于项目整体安全。

只要没手动拼接用户输入进 SQL 字符串,Laravel 默认是安全的;真正危险的是 whereRaw()、selectRaw()、orderByRaw() 这类带 Raw 的方法,以及绕过 ORM 直接用 DB::select() 拼字符串的写法。
whereRaw() 必须传第二个参数绑定变量
不传绑定数组,等于把用户输入直接扔进 SQL 执行——单引号、UNION SELECT、SLEEP(3) 全都能跑起来。
- 错误写法:
$query->whereRaw("name like '%$keyword%'")——$keyword是用户可控的,完全暴露 - 正确写法:
$query->whereRaw("name like ?", ["%{$keyword}%"])或$query->whereRaw("name like concat('%', ?, '%')", [$keyword]) - 注意:
concat()本身不影响参数化安全,但绝不能写成concat('%', '$keyword', '%')—— 只要 PHP 字符串里出现$插值,就已脱离参数化保护
动态列名、表名、排序字段必须白名单校验
字段名在 orderByRaw()、select() 甚至 DB::raw() 中都不能参数化,SQL 标准不支持,PDO 也无能为力。拼进去的不是“值”,是语法结构。
- 危险代码:
DB::table('products')->select("product_variant_{$request->input('id')}")—— 用户传1 FROM users --就可能触发异常或被利用 - 安全做法:用
in_array($field, ['id', 'name', 'created_at'], true)显式校验,或预定义映射数组:$columns = [1 => 'product_variant_1', 2 => 'product_variant_2'] - 验证层前置更稳妥:
$request->validate(['sort' => 'required|in:id,name,created_at'])
绕过 ORM 的原生查询必须用 ? 占位符
DB::select()、DB::statement() 等原生接口不自动转义,全靠你手写占位符。哪怕只漏一个,整条语句就失守。
- 高危写法:
DB::select("SELECT * FROM users WHERE name = '" . $request->input('name') . "'")—— 完全绕过所有防护 - 合规写法:
DB::select("SELECT * FROM users WHERE name = ?", [$request->input('name')]) - 慎用
DB::raw()包裹用户输入:DB::raw("'$request->input('sort')'")同样危险,单引号挡不住注入
最常被忽略的点是:ORM 安全 ≠ 项目安全。where() 链式调用再稳,也救不了 when() 里嵌套的 whereRaw() 忘传参数,或者 ignore() 验证规则里字段名为空导致的漏洞。安全边界不在框架层面,而在每一处用户输入与 SQL 结构交汇的位置。











