whereRaw默认不设防,安全使用需严格限定场景:仅用于可信标识符(须白名单校验)、值类条件优先用原生where方法、真需whereRaw时必须显式参数绑定,严禁字符串插值。

whereRaw 本身不安全,它不是“有风险”,而是“默认不设防”——框架把它设计成一条直通数据库的通道,传什么就执行什么。安全使用的关键不是怎么“加固”它,而是明确它该在哪用、怎么传参、哪些绝对不能碰。
只用于可信标识符,且必须白名单校验
字段名、表名、排序方向(ASC/DESC)这类内容无法用 ? 占位符绑定,但也不能放任用户输入直接拼入。必须提前限定范围:
- 排序字段:用 in_array(input('sort'), ['id', 'name', 'create_time'], true) 校验,非法值 fallback 到默认值
- 分组字段或 JSON 路径:如
$.tags,需预定义合法路径列表,禁止运行时拼接"$." . input('path') - 避免任何形式的字符串插值:
DB::raw("{$field} = ?")或whereRaw("{$col} > 10")都是高危操作
值类条件优先改用原生 where 方法
绝大多数场景根本不需要 whereRaw。模糊查询、范围查询、IN 条件等,框架都已封装好参数化接口:
- 代替
whereRaw("title LIKE '%" . input('q') . "%')→ 用 where('title', 'like', '%' . input('q') . '%') - 代替
whereRaw("age BETWEEN " . input('min') . " AND " . input('max'))→ 用 whereBetween('age', [input('min'), input('max')]) - 代替
whereRaw("id IN (" . implode(',', input('ids')) . ")")→ 用 whereIn('id', input('ids'))(自动处理数组绑定)
真要用 whereRaw,必须显式传参绑定
仅当涉及数据库函数、JSON 操作、GIS 计算等原生 where 不支持的结构时,才考虑 whereRaw,且动态值一律走第二个参数数组:
- 正确:whereRaw("json_contains(meta, ?)", [json_encode(['status' => 'active'])])
- 正确:whereRaw("DATE(created_at) = ?", [input('date')])
- 错误:whereRaw("DATE(created_at) = '" . input('date') . "'")(字符串拼接,无绑定)
- 错误:whereRaw("id = " . (int)input('id'))(类型转换挡不住二次利用,如日志注入)
警惕闭包和链式调用中的隐性绕过
在闭包里写 whereRaw 或 whereExists,不会自动继承外层绑定逻辑;order($field . ' ASC') 这类写法也跳过防护。这些地方和 whereRaw 一样危险:
- 闭包内所有原始 SQL 拼接都需单独做白名单或绑定
- order()、group()、having() 接收的字段名,必须和 whereRaw 中的标识符同等对待
- 检查 MySQL general_log,确认最终 SQL 是
WHERE status = ?而非WHERE status = 1 OR 1=1
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











