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 等方法仍可能存在注入风险。
- ✓保持 SQL 结构固定,将每个用户控制的值作为单独的占位符参数传入。
- ✓动态表名、列名和排序选项只能从应用维护的固定白名单中选择。
- ✓检查
Raw、Exec、Order、Select和Table等 SQL 片段方法,查找拼接或格式化。 - ✓查询前将数字标识符转换为预期 Go 类型,并处理转换错误。
如何检查代码库
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 结构。