位置:首页 > SQL > Go 1.22 项目如何防止 SQL 注入:参数绑定、白名单与 GORM 风险点

Go 1.22 项目如何防止 SQL 注入:参数绑定、白名单与 GORM 风险点

时间:2026-08-23  |  作者:风起客  |  阅读:0

必须用参数化查询防注入,占位符需匹配驱动规则(MySQL/SQLite用,PostgreSQL用$1);表名、字段名、ORDER BY等标识符须白名单校验,不可参数化。

如何在Go 1.22项目中防止SQL注入

必须用参数化查询,别拼字符串;驱动不认错占位符会直接报错;ORDER BY/表名/字段名不能参数化,得走白名单校验。

database/sql 的 Query/Exec 必须带正确占位符

Go 标准库 database/sql 本身不防注入,它只负责传参——真正起作用的是你写的 SQL 字符串干不干净。MySQL 和 SQLite 驱动只认 ,PostgreSQL 驱动只认 $1$2。混用会立刻失败:

  • sql: expected 0 arguments, got 1:说明占位符没被识别,参数被当字面量丢进去了
  • ERROR: syntax error at or near "123":常见于 PostgreSQL 里误写 ,驱动把它当普通字符解析了

实操建议:

  • 查清你用的驱动(github.com/go-sql-driver/mysql 还是 github.com/lib/pq),严格按其规则写占位符
  • 永远用 db.Query("SELECT * FROM users WHERE id = AND status = ", id, "active"),而不是 fmt.Sprintf("... id = %d", id)
  • 参数类型要匹配:传 int64 没问题,但传 nil 给非 NULL 字段会 panic,需用 sql.NullInt64 等显式类型

动态表名、字段名、ORDER BY 必须白名单校验

SQL标准是不允许对标识符(identifier)进行参数化的,因此所有驱动都会拒绝诸如ORDER BY SELECT FROM users这类语句,运行时会直接报错。有些人可能会将其改成fmt.Sprintf("ORDER BY %s", input),但这样做就相当于把数据库毫无保护地暴露出去了。

实操建议:

  • 排序字段只允许从固定集合选:validSortFields := map[string]bool{"created_at": true, "name": true, "score": true},查之前先判断 validSortFields[input]
  • 表名映射用常量或 switch:switch input { case "prod": tableName = "users_prod"; case "test": tableName = "users_test" },别拼 "users_" + input
  • LIMITOFFSETGROUP BY 同理,数值类参数可转 int 并做范围检查(如 limit <= 100),字符串类必须白名单

GORM 等 ORM 也要小心 Raw() 和 Table() 的陷阱

GORM 默认开启 PrepareStmtdb.Where("name = ", name).Find(&u) 是安全的。但一旦调用 Raw() 或手动拼接表名,防护就失效了。

实操建议:

  • 禁用 Raw():除非绝对必要,否则不用;真要用,也只拼白名单内的字段或表名,参数仍走 $1
  • Table(tableName) 替代字符串拼接:db.Table(tableName).Where("id = ", id).Find(&u),前提是 tableName 来自配置或枚举,不是用户输入
  • 检查 GORM 日志是否输出原始 SQL——如果看到 SELECT * FROM users WHERE name = 'admin'' OR ''1''=''1' 这种,说明参数没绑上,得回溯代码找拼接点

Scan 接收 NULL 时类型必须显式声明

Scan 不参与防注入,但它出错会暴露结构、引发 panic,甚至间接导致逻辑异常。比如数据库字段允许 NULL,但你用 string 接收,遇到 NULL 就 panic;或者用 *string 却没判空,后续解引用崩掉。

实操建议:

  • 字段可能为 NULL 时,必须用 sql.NullStringsql.NullInt64sql.NullBool 等类型接收
  • 扫描后检查 .Valid 字段:if name.Valid { fmt.Println(name.String) },别直接用 name.String
  • 结构体字段加 sql tag 时注意:没有 omitemptyNULL 字段会覆盖已有值,容易引发静默数据污染

最易被忽略的点是:白名单校验和参数绑定是两套机制,缺一不可。占位符只保数据安全,保不住标识符;白名单只保标识符安全,保不住数据语义。两者必须同时落地,漏一个就等于开了后门。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多