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

Gin SQL注入防范

SQL 注入是 Web 应用最常见的安全漏洞之一,Gin 框架下需正确使用数据库操作才能有效防范。

SQL注入原理

攻击者通过构造恶意输入,改变原 SQL 语句逻辑,实现未授权数据访问或破坏。

Go
// 危险示例:字符串拼接 SQL
func GetUser(db *sql.DB, username string) (*User, error) {
    query := "SELECT * FROM users WHERE username = '" + username + "'"
    // 输入: admin' OR '1'='1
    // 实际执行: SELECT * FROM users WHERE username = 'admin' OR '1'='1'
    // 结果: 返回所有用户
}

参数化查询(核心防护)

使用占位符,让数据库驱动处理参数转义。

Go
// 安全示例:参数化查询
func GetUser(db *sql.DB, username string) (*User, error) {
    query := "SELECT * FROM users WHERE username = ?"
    row := db.QueryRow(query, username)
    // 数据库驱动自动处理特殊字符转义
}

// Gin 路由中使用
func GetUserHandler(c *gin.Context) {
    username := c.Param("username")
    user, err := GetUser(db, username)
    if err != nil {
        c.JSON(500, gin.H{"error": "查询失败"})
        return
    }
    c.JSON(200, user)
}

GORM 安全使用

Go
// 安全:使用 Where 参数绑定
user := User{}
db.Where("username = ?", username).First(&user)

// 安全:使用 First 的主键查询
db.First(&user, userId) // 自动参数化

// 危险:原生 SQL 拼接
db.Raw("SELECT * FROM users WHERE username = '" + username + "'").Scan(&user)

// 安全:原生 SQL 参数化
db.Raw("SELECT * FROM users WHERE username = ?", username).Scan(&user)

// 安全:Map 条件查询
db.Where(map[string]interface{}{"username": username}).First(&user)

// 安全:Struct 条件查询
db.Where(&User{Username: username}).First(&user)

输入验证与过滤

Go
// 使用 validator 验证输入
type LoginRequest struct {
    Username string `form:"username" binding:"required,alphanum,min=3,max=20"`
    Password string `form:"password" binding:"required,min=6,max=50"`
}

func LoginHandler(c *gin.Context) {
    var req LoginRequest
    if err := c.ShouldBind(&req); err != nil {
        c.JSON(400, gin.H{"error": "参数格式错误"})
        return
    }
    // 验证通过,进行数据库查询
}

常见注入场景与防护

场景危险写法安全写法
条件查询"WHERE id=" + idWhere("id = ?", id)
模糊查询"LIKE '%" + keyword + "%'"Where("name LIKE ?", "%"+keyword+"%")
排序字段"ORDER BY " + sort白名单验证排序字段
表名拼接"FROM " + table禁止动态表名或严格白名单

排序字段白名单验证

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

func validateSortField(field string) string {
    if allowedSortFields[field] {
        return field
    }
    return "id" // 默认排序字段
}

func ListUsers(c *gin.Context) {
    sort := c.DefaultQuery("sort", "id")
    sort = validateSortField(sort)
    order := c.DefaultQuery("order", "asc")
    if order != "asc" && order != "desc" {
        order = "asc"
    }

    var users []User
    db.Order(sort + " " + order).Find(&users)
    c.JSON(200, users)
}

注意:排序字段和表名无法使用参数化,必须使用白名单严格验证。

要点总结

  1. 始终使用参数化查询,禁止字符串拼接 SQL
  2. GORM 使用 Where("field = ?", value) 而非字符串拼接
  3. 输入验证是第一道防线,使用 validator 约束格式
  4. 排序、表名等动态字段使用白名单验证
  5. 代码审计时搜索 db.Raw(Exec(、字符串拼接模式
  6. 定期使用 SQL 注入扫描工具检测

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

← 上一篇 Gin RBAC权限模型实现
下一篇 → Gin XSS过滤
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

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

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