全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-21 8 分钟 ✍️ juanwangdev

GORM SQL 注入防护

GORM 默认使用参数化查询,但不当使用 Raw() 和字符串拼接仍会引入 SQL 注入风险,需严格遵循安全查询规范。

SQL 注入原理

注入攻击示例

Go
// 危险示例:字符串拼接
userID := "1 OR 1=1"
db.Where("id = " + userID).Find(&users)
// 生成 SQL: SELECT * FROM users WHERE id = 1 OR 1=1
// 结果:返回全部数据

注意: 任何将用户输入直接拼接到 SQL 语句的行为都可能引入注入漏洞。

参数化查询

安全的 Where 条件

Go
// 正确:参数化查询
db.Where("id = ?", userID).Find(&users)
// 生成 SQL: SELECT * FROM users WHERE id = ? (参数绑定)

// 多个参数
db.Where("name = ? AND age > ?", name, age).Find(&users)

// IN 查询
db.Where("id IN ?", []int{1, 2, 3}).Find(&users)

Map 条件

Go
// Map 参数化
db.Where(map[string]interface{}{
    "name":   "张三",
    "status": "active",
}).Find(&users)
// 生成 SQL: SELECT * FROM users WHERE name = ? AND status = ?

Struct 条件

Go
// Struct 参数化(仅非零值字段生效)
db.Where(&User{Name: "张三", Status: "active"}).Find(&users)

Raw SQL 安全使用

参数化 Raw 查询

Go
// 正确:使用参数绑定
db.Raw("SELECT * FROM users WHERE id = ? AND status = ?", userID, status).Scan(&users)

// 错误:拼接 SQL
db.Raw("SELECT * FROM users WHERE id = " + userID).Scan(&users) // 危险

Named SQL

Go
// 命名参数
db.Raw(
    "SELECT * FROM users WHERE name = @name AND age > @age",
    sql.Named("name", name),
    sql.Named("age", age),
).Scan(&users)

动态排序字段防护

白名单校验

Go
var allowedSortFields = map[string]bool{
    "name":       true,
    "created_at": true,
    "age":        true,
}

func SafeOrder(db *gorm.DB, sortField string, asc bool) *gorm.DB {
    if !allowedSortFields[sortField] {
        sortField = "created_at" // 默认值
    }
    
    if asc {
        return db.Order(sortField + " ASC")
    }
    return db.Order(sortField + " DESC")
}

// 使用
db = SafeOrder(db, userInputSortField, true)

注意: ORDER BY 后的字段无法使用参数绑定,必须通过白名单校验防止注入。

模糊查询安全

参数化 LIKE 查询

Go
// 正确:参数中拼接通配符
keyword := "%张%"
db.Where("name LIKE ?", keyword).Find(&users)

// 错误:SQL 中拼接
db.Where("name LIKE '%" + keyword + "%'").Find(&users) // 危险

// 安全封装
func LikeQuery(db *gorm.DB, field, value string) *gorm.DB {
    return db.Where(field+" LIKE ?", "%"+value+"%")
}

批量插入安全

参数化批量插入

Go
// GORM 自动参数化批量插入
users := []User{
    {Name: "张三", Age: 20},
    {Name: "李四", Age: 25},
}
db.Create(&users)
// 生成 SQL: INSERT INTO users (name, age) VALUES (?, ?), (?, ?)

// 原生批量插入也需参数化
db.Exec(
    "INSERT INTO users (name, age) VALUES (?, ?), (?, ?)",
    "张三", 20, "李四", 25,
)

防注入检查清单

安全实践汇总

场景安全做法危险做法
Where 条件Where("id = ?", id)Where("id = " + id)
Raw 查询Raw("SELECT ... WHERE id = ?", id)Raw("SELECT ... WHERE id = " + id)
排序字段白名单校验直接使用用户输入
LIKE 查询Like "%"+value+"%" 作为参数SQL 中拼接通配符
表名/列名白名单或硬编码用户输入直接使用

注意: 表名和列名无法使用参数绑定,必须通过白名单校验或硬编码,严禁直接使用用户输入。

要点总结

  • GORM 的 Where() 方法默认使用参数化查询,安全防注入
  • 严禁使用字符串拼接用户输入构建 SQL 条件
  • Raw() 查询必须使用 ? 占符绑定参数,禁止拼接
  • ORDER BY 后的排序字段需白名单校验,无法参数化
  • 表名和列名无法参数化,必须硬编码或白名单校验
  • LIKE 查询应将通配符拼接到参数值中,而非 SQL 中

存放路径:D:\git2\jwdev\articles\GORM\专家\安全与数据保护\SQL 注入防护.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 GORM 迁移脚本编写
下一篇 → GORM 敏感数据加密存储
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库