必须使用参数占位符(如?或$1)而非字符串拼接来防止SQL注入;sql.RawBytes仅用于读取二进制字段,不可用于拼接SQL;动态表名/字段名需白名单校验;ORM应禁用Raw()并启用PrepareStmt;JSON中的SQL片段同样需严格校验。
用
的
和
时必须带参数占位符
Go 原生
包本身不拼接 SQL 字符串,但开发者一不小心就手写
或字符串拼接,直接把用户输入塞进查询里。这是最常见、最危险的入口。
正确做法永远是用
占位符(MySQL/SQLite)或
(PostgreSQL),让驱动做参数绑定。数据库看到的不是“拼出来的字符串”,而是独立的值,根本不会当 SQL 解析。
错:
—— 输入
就完蛋
对:
—— 驱动自动转义并隔离
PostgreSQL 要用
、
:
不是用来绕过参数绑定的
有人以为
是“原始数据容器”,能用来动态拼 SQL,其实它只是读取二进制字段(比如
)时的临时缓冲区类型,跟防注入毫无关系。拿它拼接查询等于自废防御。
常见错误场景:从配置表读 SQL 模板,再用
拼上用户 ID——这和直接字符串拼接没区别,只是换了个难懂的写法。
立即学习
“
go语言免费学习笔记(深入)
”;
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
只该出现在
接收列值时,比如读
任何需要“动态表名”“动态字段名”的需求,都不能靠参数绑定解决,得走白名单校验或重构设计
真要拼表名?先查一遍
确认存在,再硬编码比对,别信任何用户输入
ORM(如 GORM)开启
并禁用原生 SQL 拼接
GORM 默认会 prepare 语句,但如果你调用
或手动用
执行字符串,防护就失效了。尤其
+
组合,极易写出带拼接的“伪安全”代码。
默认开启
时,
是安全的
但
—— 表名未校验,照样中招
禁用
,改用
:
,前提是
来自枚举或配置项
JSON 字段里的 SQL 片段不是“免检区”
有些服务把查询条件存成 JSON(比如搜索过滤器),后端解析后拼成 SQL。这时候容易误以为“JSON 是数据,不是代码”,放松校验。但只要最终进了
的字符串参数,就是注入温床。
解析 JSON 后得到的
,不能直接
进 SQL
字段名(如
)必须映射到预设白名单:
操作符(
,
)也要限制范围,避免注入
类逻辑
数值类值可直接参数化,字符串类值必须走
而非
真正麻烦的从来不是语法怎么写,而是哪一层该信任输入、哪一层必须掐死拼接——边界模糊的地方,往往就是漏洞藏身的位置。
database/sqlQueryExecdatabase/sqlfmt.Sprintf?$1db.Query("SELECT * FROM users WHERE name = '" + name + "'")' OR 1=1 --db.Query("SELECT * FROM users WHERE name = ?", name)$1$2db.Query("SELECT * FROM users WHERE id = $1 AND status = $2", id, status)sql.RawBytessql.RawBytesBLOBsql.RawBytessql.RawBytesScanMEDIUMBLOBINFORMATION_SCHEMA.TABLESPrepareStmtSession(&gorm.Session{PrepareStmt: false})Raw()Raw()Scan()PrepareStmtdb.Where("name = ?", name).Find(&u)db.Raw("SELECT * FROM " + tableName + " WHERE id = ?", id).Scan(&u)Raw()Table(tableName)db.Table(tableName).Where("id = ?", id).Find(&u)tableNamedb.Querymap[string]interface{}fmt.Sprintf"user_name"validFields := map[string]bool{"name": true, "email": true}"gt""like"OR 1=1LIKE ?LIKE '%"+v+"%'