sql注入高发区是字符串拼接、手写sql模板和fmt.sprintf塞入用户输入;应坚持参数化传参+类型绑定,动态字段名/表名需白名单校验,泛型gorm和gen可提升类型安全与编译期防护。

直接用 db.Where 拼接字符串、手写 SQL 模板、或把用户输入塞进 fmt.Sprintf,这三类操作在 GORM 项目里就是 SQL 注入的高发区。只要坚持参数化传参 + 类型绑定,99% 的注入风险能被编译期或运行时拦截。
别用字符串拼接构造 WHERE 条件
这是最常见也最危险的习惯。比如写成 db.Where("name = '" + username + "'"),攻击者传入 admin' OR '1'='1 就能绕过验证。
- ✅ 正确做法:所有变量一律走占位符,
db.Where("name = ?", username)或db.Where("name IN ?", userNames) - ⚠️ 注意点:
IN子句不能直接传 slice 给单个?,得用db.Where("name IN ?", []string{"a","b"}),GORM 会自动展开为IN ('a','b') - ❌ 禁止对字段名、表名做动态拼接,它们不属于“值”,无法用占位符保护。如需动态表名,必须白名单校验或硬编码分支
泛型版 GORM(gorm.G[T])强制类型安全
传统 *gorm.DB 是泛型擦除的,db.First(&order) 却查 User 表也不会报错;而 gorm.G[User](db) 把模型和查询强绑定,类型错直接编译失败。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- ✅ 必须带
context:gorm.G[User](db).Where("name = ?", name).First(ctx, &user),否则无法支持超时控制 - ✅ 关联查询也受保护:
gorm.G[User](db).Preload("Orders").Find(ctx, &users),不会因结构体字段名写错导致静默查错表 - ⚠️ 注意:泛型 API 要求 GORM >= v1.30.0,旧项目升级后需检查所有
First/Find/Create调用是否补全了ctx和类型参数
GEN 自动生成代码,从源头掐断注入可能
GEN 不是“更高级的 GORM”,而是把 SQL 模板提前编译成类型安全的方法。你写的注释 // select * from users where name = {{.name}} and age > {{.minAge}},会被转成带校验的 Go 方法,连字段名拼错都会编译报错。
- ✅ 启动时用
g.UseDB(db)复用连接,生成的 query 代码自带预编译逻辑,所有参数走Query/Exec底层,不拼 SQL 字符串 - ✅ 自定义 SQL 必须写在 interface 方法的 doc comment 里,GEN 才会识别并生成安全 wrapper;裸写
db.Raw()仍需手动防护 - ⚠️ 容易踩坑:生成的
query包默认启用WithContext,如果忘记传ctx,调用会 panic;可加gen.WithoutContext配置项关闭,但不推荐
真正难防的不是语法层面的注入,而是业务逻辑里“本该校验却没校验”的字段——比如前端传来的 status 值,没做白名单限制就直接进 WHERE status = ?,哪怕用了占位符,恶意值仍可能触发越权查询。类型安全和参数化只是基础防线,字段语义校验得落在业务层。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










