gorm不自动防注入,关键在正确使用双参数where等方法;单参数传字符串即裸奔,raw需白名单校验结构部分,scan须严格匹配字段顺序与类型。

GORM 本身不自动防注入,关键在你是否用对了 Where、First 等方法的参数化签名——传两个参数才安全,只传一个字符串就等于裸奔。
为什么 db.Where("name = '" + name + "'") 是高危写法
这种写法把用户输入直接拼进 SQL 字符串里,数据库驱动完全不干预。哪怕 name 是 "admin' OR 1=1 --",最终执行的就是:SELECT * FROM users WHERE name = 'admin' OR 1=1 --',条件恒真。
-
db.Where("name = ?", name)✅:GORM 调用的是双参数重载版本,底层走预编译 + 参数绑定,name被当纯数据处理 -
db.Where("name = '" + name + "'")❌:单参数调用,GORM 当作原生 SQL 片段透传,不加任何防护 -
db.Where("age > ?", ageStr).Where("status = '" + status + "'")❌:前半段安全,后半段崩盘,混合写法让整条链失去防护
Raw() 是 GORM 最危险的入口,必须白名单校验结构部分
db.Raw() 绕过所有 ORM 层检查,直连驱动。表名、列名、ORDER BY 字段这些“标识符”无法用 ? 占位,只能靠代码硬约束。
- 表名动态拼接?先查白名单:
validTables := map[string]bool{"users": true, "orders": true, "products": true},不在其中就return errors.New("invalid table") - 排序字段来自 URL 参数?只允许
"created_at"、"name"、"id",用map[string]bool快速判断 - 别信
strings.ReplaceAll(input, "'", "''")或正则过滤——PostgreSQL 支持$1、Unicode 注释符、多字节绕过,黑名单无效
Scan 不防注入,但字段顺序错配会导致静默数据错乱
Scan 只管把查询结果按 SELECT 后的**列顺序**和**类型**填进变量,和 SQL 构造无关。但它一旦出错,不会报注入,而是把邮箱值扫进 ID 字段、NULL 写进 string 导致 panic。
- 永远显式写字段:
SELECT id, name, email FROM users,不用SELECT * - 接收时用结构体或具名变量:
err := row.Scan(&u.ID, &u.Name, &u.Email),别堆&id, &name, &email - 可能为 NULL 的字段,必须用
sql.NullString、sql.NullInt64等类型接收
PrepareStmt 开关影响性能,不改变安全性本质
gorm.Config{PrepareStmt: true} 让每次查询走预编译路径,复用执行计划,主要价值在性能。它不会让 Raw() 或字符串拼接变安全。
- 开启后,
db.Where("name = ?", name).First(&u)会复用预编译语句,但安全性仍取决于你是否用了? - 关闭后,GORM 可能退化为每次拼 SQL 字符串再执行——此时若你误用
Where("name = '" + name + "'"),风险加倍 - 真正要禁用的是
Raw()和手写字符串拼接,不是PrepareStmt
最易被忽略的一点:多人协作时,表结构加字段或改顺序,Scan 和 SELECT 语句极易不同步,而这类错误不报注入,只悄悄错位——建议用单元测试固定字段映射关系。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











