db::raw()本身不防sql注入,仅原样插入字符串;若拼接用户输入则危险,应改用selectraw()绑定参数或白名单校验标识符。

DB::raw() 本身不防注入,它只是生成一个原始表达式
DB::raw() 返回的是一个 Illuminate\Database\Query\Expression 实例,它不会做任何参数绑定或转义——它只负责把传进去的字符串原样塞进 SQL 的对应位置。这意味着,如果你把用户输入直接拼进 DB::raw() 的字符串里,就等于亲手打开 SQL 注入大门。
常见错误写法:
DB::table('users')->select(DB::raw("CONCAT(first_name, ' ', last_name) AS full_name"))->where('id', $id)->get(); // ✅ 安全,无用户输入
DB::table('users')->select(DB::raw("CONCAT('{$firstName}', ' ', '{$lastName}')"))->get(); // ❌ 危险!$firstName 和 $lastName 是用户输入
关键点:只要 DB::raw() 里出现 "{$var}"、'. $var .' 或任何字符串拼接,且 $var 来自请求、路由、表单等不可信来源,就存在风险。
DB::raw() 必须配合 whereRaw() 或 selectRaw() 的参数绑定才安全
DB::raw() 单独使用无法绑定参数,但你可以把它和真正支持绑定的方法组合起来,让值走占位符通道。
- 不要用
DB::raw()拼接动态值,改用selectRaw()+?占位符 - 不要手动拼
ORDER BY {$sortField},改用白名单校验 +orderByRaw() - 避免在
DB::raw()中处理 JSON 字段查询逻辑,优先用whereJsonContains()等语义化方法
正确示例:
DB::table('users')->selectRaw('CONCAT(?, " ", ?) AS full_name', [$firstName, $lastName])->get(); // ✅ 值走绑定
$allowedSorts = ['name', 'email', 'created_at'];<br>if (! in_array($sort, $allowedSorts)) {<br> abort(400);<br>}<br>DB::table('users')->orderByRaw("{$sort} ?")->get(); // ❌ 错误:? 在 orderByRaw 里无效<br>DB::table('users')->orderBy($sort)->get(); // ✅ 直接用 orderBy,框架会校验字段名
哪些地方不能靠 DB::raw() 绑定,必须白名单硬控
占位符 ? 和命名参数只能绑定「值(values)」,不能绑定「标识符(identifiers)」——也就是表名、列名、函数名、排序方向(ASC/DESC)、GROUP BY 字段这些。
以下操作无法用参数绑定防护,必须提前验证:
-
DB::table($tableName)→ 验证$tableName是否在['users', 'posts', 'comments']中 -
select($column)→ 若$column动态来自请求,需in_array($column, ['id', 'title', 'status']) -
orderBy($field, $direction)→$direction必须是'ASC'或'DESC',不能直接拼 -
groupBy($groupField)→ 同样需白名单,不能接受任意字符串
典型翻车场景:
$sql = "SELECT * FROM {$table} WHERE status = ?";<br>DB::select($sql, [$status]); // ❌ 表名未校验,$table = "users; DROP TABLE users; --" 就完了
替代方案比死磕 DB::raw() 更安全也更可读
很多你以为非得用 DB::raw() 的场景,Laravel 其实早有封装好的安全方法。
- JSON 字段查询:用
whereJsonContains('metadata', 'active'),而不是whereRaw("metadata->'$.status' = ?") - 日期比较:用
whereDate('created_at', today()),而不是whereRaw("DATE(created_at) = ?") - 聚合计算:用
selectRaw('SUM(price) as total')+ 绑定值,但别把整个SUM(price * ?)的乘数当用户输入 - 模糊搜索:坚持用
where('name', 'like', "%{$search}%"),它底层仍走预处理,比手写whereRaw("name LIKE '%{$search}%'")强十倍
真正需要 DB::raw() 的,往往只是静态表达式,比如 DB::raw('NOW()')、DB::raw('1 AS is_default') —— 这类没有变量参与,天然免疫注入。
最常被忽略的一点:DB::raw() 安全与否,不取决于它自己,而取决于你有没有把用户输入塞进它的字符串里。只要字符串里有变量插值,就必须换思路——要么白名单,要么改用支持绑定的接口,要么把计算逻辑移到 PHP 层。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











