高级主题

安全

qianmoQqianmoQ· 更新于 2026-09-22· 阅读 5 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

GORM 使用 database/sql 的参数占位符构建 SQL 语句,会自动转义参数以避免 SQL 注入

注意 日志记录器输出的 SQL 语句与实际执行的语句不同,未完全转义,请谨慎在 SQL 控制台中复制执行

查询条件

用户输入应仅作为参数使用,例如:

userInput := "jinzhu;drop table users;"

db.Where("name = ?", userInput).First(&user)

db.Where(fmt.Sprintf("name = %v", userInput)).First(&user)

内联条件

db.First(&user, "name = ?", userInput)

db.First(&user, fmt.Sprintf("name = %v", userInput))

当通过用户输入获取数字主键对象时,应检查变量类型:

userInputID := "1=1;drop table users;"

id, err := strconv.Atoi(userInputID)
if err != nil {
    return err
}
db.First(&user, id)

db.First(&user, userInputID)

SQL 注入方法

为支持部分功能,某些输入未被转义,使用用户输入配合这些方法时需格外谨慎:

db.Select("name; drop table users;").First(&user)
db.Distinct("name; drop table users;").First(&user)

db.Model(&user).Pluck("name; drop table users;", &names)

db.Group("name; drop table users;").First(&user)

db.Group("name").Having("1 = 1;drop table users;").First(&user)

db.Raw("select name from users; drop table users;").First(&user)

db.Exec("select name from users; drop table users;")

db.Order("name; drop table users;").First(&user)

db.Table("users; drop table users;").Find(&users)

db.Delete(&User{}, "id=1; drop table users;")

db.Joins("inner join orders; drop table users;").Find(&users)

db.InnerJoins("inner join orders; drop table users;").Find(&users)

db.Exec("UPDATE users SET name = '?' WHERE id = 1", gorm.Expr("alice'; drop table users;-- "))

db.Where("id=1").Not("name = 'alice'; drop table users;").Find(&users)

db.Where("id=1").Or("name = 'alice'; drop table users;").Find(&users)

db.Find(&User{}, "name = 'alice'; drop table users;")

db.First(&users, "2 or 1=1-- ")

db.FirstOrCreate(&users, "2 or 1=1-- ")

db.FirstOrInit(&users, "2 or 1=1-- ")

db.Last(&users, "2 or 1=1-- ")

db.Take(&users, "2 or 1=1-- ")

避免 SQL 注入的通用原则是不要信任用户提交的数据,可通过白名单验证测试用户输入是否符合已知、合法、预定义的输入范围,且使用用户输入时仅将其作为参数传递。

GitHub tag (latest SemVer)

评论

登录后参与评论

正在加载评论…