hyperf的querybean仅对条件值自动绑定,字段名、表名、排序等动态部分必须白名单校验;where(['field'=>$val])安全,但where([$userfield=>$val])危险;orderby、groupby、from、havingraw等均不自动过滤,须严格校验输入。

Hyperf 的 QueryBean 本身不自动做参数绑定,所有字段名、表名、排序、分组等动态部分若直接拼入 SQL,就会触发 SQL 注入——它不是 ActiveRecord 那种全封装模型,而是更轻量、更贴近原生查询的抽象层。
QueryBean 的 where() 看似安全,但只对值有效
where() 方法对数组形式的条件(如 ['status' => $input])确实会走 PDO 预处理绑定,这点和 Yii 的 where() 类似。但它完全不管键名本身是否可信。
- ✅ 安全:
->where(['name' => $_GET['name']])→name = ?绑定字符串 - ❌ 危险:
->where([$_GET['field'] => 'admin'])→ 字段名被拼进 SQL,变成`username` = ?或更糟的`user_name`; DROP TABLE users; --` = ? - ⚠️ 模糊查询也只保值:
->where(['LIKE', 'title', '%' . $_GET['q']] )中title是硬编码才安全;若写成->where(['LIKE', $_GET['col'], $_GET['q']]),列名就失控了
orderBy / groupBy / having 等动态结构必须白名单校验
Hyperf 不会对 orderBy() 参数做任何过滤,传入 "id; DROP TABLE users--" 会原样进 SQL。不能依赖“框架应该拦住”,得自己卡住入口。
- 只允许预设字段:
$allowedSorts = ['id', 'created_at', 'status', 'amount']; - 校验后才构造:
if (in_array($sort, $allowedSorts, true)) { $query->orderBy($sort, $dir); } - 别用字符串拼:
->orderBy($_GET['sort'] . ' ' . $_GET['dir'])——dir同样要限制为'ASC'或'DESC' - 连表别名、
AS别名、CASE WHEN中的字段引用,只要来自用户输入,一律先过白名单或正则(如/^[a-zA-Z_][a-zA-Z0-9_]*$/)
手动 build SQL 时,必须用 bindValue() 而非字符串插值
一旦你调用 new Query() 或 Db::raw() 构造原始 SQL,Hyperf 就彻底交出控制权。此时安全责任 100% 在你手上。
- ❌ 错误:
Db::select("SELECT * FROM {$table} WHERE id = " . (int)$_GET['id']);—— 表名未校验,ID 强转整数也不防表名注入 - ✅ 正确:
Db::select("SELECT * FROM `?` WHERE id = ?", [$tableName, $id]);(注意:Hyperf 的?占位符仅支持值绑定,表名/字段名仍需白名单) - 更稳妥写法:
$stmt = Db::getPdo()->prepare("SELECT * FROM {$safeTable} WHERE id = :id"); $stmt->bindValue(':id', $id, PDO::PARAM_INT); $stmt->execute(); - IN 查询别手拼:
whereIn('status', $ids)是安全的;但若用 raw,就得用str_repeat('?,', count($ids) - 1) . '?'+bindValues()
容易被忽略的三个高危点
很多团队在 Code Review 里能发现 where 拼接,却常漏掉这些:
-
QueryBean::from()的第一个参数是表名,若来自路由参数或配置项,没做白名单就等于敞开大门 -
havingRaw()和whereRaw()默认不绑定任何东西,哪怕你写了whereRaw('sum(price) > ?', [$min]),前面的sum(price) > ?结构仍是用户可控的——攻击者可填sum(price) > 0 UNION SELECT password FROM users - 使用
Db::transaction()时,在事务块内混用 raw 查询和普通 query,容易因上下文切换放松警惕,尤其当多个查询复用同一变量时











