FlawOpen

flawopen.com/Go 中的 SQL 注入/GORM Raw SQL 与 SQL 注入

GORM Raw() 能防止 SQL 注入吗?Go 参数绑定指南

CWE-89: SQL Injection参考页面
简短回答

可以把占位符想成装值的密封信封:数据库驱动会把值与 SQL 指令分开发送。只要占位符保留在查询中,并把值作为单独参数传入,GORM Raw() 就能安全绑定。若把用户输入格式化进 SQL 字符串,就把信封和指令混在一起,可能改变查询。

不安全
// 用户可控文本变成 SQL 语法
db.Raw(fmt.Sprintf(
  "SELECT * FROM users WHERE id = %s",
  userID,
)).Scan(&user)
安全
// 驱动将 userID 作为值绑定
db.Raw(
  "SELECT * FROM users WHERE id = ?",
  userID,
).Scan(&user)

GORM Raw SQL 安全规则与参数绑定

当占位符留在 SQL 中、参数单独传递时,GORM 和 Go 的 database/sql 会绑定数据值,例如 db.Where("name = ?", userInput) 或 db.Raw("SELECT ... WHERE id = ?", userID)。占位符代表值而非 SQL 语法:绑定值无法保护表名、列名、排序方向或运算符。动态标识符应从固定白名单中选择。若将用户输入拼接进 SQL 片段,Order、Select、Table 和 Raw 等方法仍可能存在注入风险。

如何检查代码库

rg -n --glob '*.go' '\.(Raw|Exec|Order|Select|Table)\s*\(' . rg -n --glob '*.go' 'fmt\.(Sprintf|Sprint)' .

GORM Raw SQL 与参数绑定常见问题

GORM 的链式查询方法总是安全吗?

不一定。像 Where("name = ?", input) 这样单独传值的条件会使用参数绑定。若把输入拼接进条件字符串或直接传入原始 SQL 语法,仍可能注入查询。有些方法接收未转义的标识符或 SQL 片段;应检查参数,并用白名单限制动态结构。

占位符可以绑定表名或列名吗?

不可以。占位符表示数据值。动态标识符或排序方向应从应用定义的固定选项中选择,并且只将已验证的常量插入 SQL 结构。

官方来源与参考资料

另请参阅 SQL 注入(CWE-89):原理与各编程语言的防护方法 — flawopen.com 转义引号足以防止 SQL Injection 吗? 使用 ORM 足以防止 SQL 注入吗? Knex.js 能防止 SQL 注入吗? MyBatis ${} 与 #{}:防止 SQL Injection MySQLi 与 PDO:安全使用预处理语句 NHibernate 能防止 SQL 注入吗?