Go防SQL注入最硬底线是禁用字符串拼接、只用Query/Exec参数化传参;MySQL/SQLite用?,PostgreSQL用$1,动态表名等须白名单校验。

database/sql 本身不防注入,但只要你不用字符串拼接构造 SQL,只通过 Query、Exec、QueryRow 等方法传参,就基本不会中招——这是 Go 防注入最硬的底线。
用 Query 和 Exec 时必须带占位符,别拼字符串
Go 的注入漏洞 95% 以上都来自手写 "SELECT * FROM users WHERE id = " + userID 这类代码。哪怕加了引号、转义单引号,也挡不住 admin' -- 或 Unicode 空格绕过。
- MySQL/SQLite 驱动只认
?:例如db.Query("SELECT name FROM users WHERE status = ? AND age > ?", "active", 18) - PostgreSQL 驱动只认
$1、$2:例如db.Query("SELECT name FROM users WHERE id = $1 AND deleted = $2", 123, false) - 混用占位符会直接报错:
sql: expected 0 arguments, got 1或ERROR: syntax error at or near "123" -
fmt.Sprintf、+、strings.Join拼 SQL 字符串,等于主动关闭防护
ORDER BY、表名、字段名不能用 ? 或 $1
SQL 标准不允许参数化标识符(identifier),驱动层根本不支持。试图写 ORDER BY ? 会 panic,而有人接着改成 fmt.Sprintf("ORDER BY %s", input),这就彻底裸奔了。
- 排序字段必须白名单校验:比如只允许
[]string{"created_at", "name", "score"},用map[string]bool快速判断 - 表名映射建议用常量或 switch:用户输入
"prod"→ 实际查"users_prod",而不是"users_" + input - 排序方向(
ASC/DESC)同样要白名单,不能靠参数传 - 别信
strings.ReplaceAll(input, "'", "")这类过滤——攻击者用/**/、换行、零宽空格就能绕过
Scan 接收结果时类型和 NULL 必须显式处理
Scan 不参与防注入,但它出错会暴露结构、引发 panic,甚至间接导致逻辑异常。常见错误不是注入,但危害不亚于注入。
立即学习“go语言免费学习笔记(深入)”;
- 数据库字段可能为
NULL,却用普通string接收 →panic: sql: Scan error on column index 0: unsupported Scan, storing driver.Value type <nil> into type *string - 所有可能为 NULL 的字段,必须用
sql.NullString、sql.NullInt64等类型接收 - 扫描到结构体时,字段顺序必须和
SELECT列严格一致;用SELECT id, name AS username就得对应结构体字段Username string - 日志里打印原始 SQL 时,必须确认该 SQL 来自预编译语句,否则
log.Printf("executing: %s", query)可能泄露拼接痕迹
ORM 如 gorm 的 Raw 方法不自动防注入
ORM 不是免检金牌。你调 db.Raw("SELECT * FROM " + tableName + " WHERE id = ?", id),表名没校验,照样中招。很多翻车发生在“以为用了 ORM 就安全”这个错觉里。
-
db.Table(tableName).Where("id = ?", id).Find(&u)是安全的,前提是tableName来自配置或枚举 -
db.Where("name = '" + name + "'")或db.Where("age > " + ageStr)—— 后半段没走占位符,直接崩 -
Raw+Scan组合极易写出伪安全代码,比如db.Raw("UPDATE users SET status = ? WHERE id IN ("+idsStr+")", status) - 禁用
Raw,改用链式构建;若必须动态表名,先做白名单比对再进Table()
真正难的从来不是“怎么写安全 SQL”,而是当业务要求“按用户选的字段排序”“查不同租户的分表”“动态拼接查询条件”时,如何在白名单、映射表、配置驱动之间守住那条线——漏掉任何一个标识符校验点,前面所有参数化都白做。


















