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

Gin 中间件安全控制

中间件是 Gin 安全控制的核心环节,统一处理请求验证、安全头部、跨域控制等安全措施。

安全头部中间件

Go
func SecurityHeadersMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 防止 XSS 攻击
        c.Header("X-XSS-Protection", "1; mode=block")

        // 防止 MIME 类型嗅探
        c.Header("X-Content-Type-Options", "nosniff")

        // 防止点击劫持
        c.Header("X-Frame-Options", "DENY")

        // 强制 HTTPS(生产环境启用)
        c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")

        // 内容安全策略
        c.Header("Content-Security-Policy", "default-src 'self'")

        // 引用策略
        c.Header("Referrer-Policy", "strict-origin-when-cross-origin")

        // 权限策略
        c.Header("Permissions-Policy", "geolocation=(), microphone=()")

        c.Next()
    }
}

func main() {
    r := gin.Default()
    r.Use(SecurityHeadersMiddleware())
    r.Run(":8080")
}

CORS 跨域控制

基础 CORS 配置

Go
func CORSMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Header("Access-Control-Allow-Origin", "*")
        c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
        c.Header("Access-Control-Expose-Headers", "Content-Length")
        c.Header("Access-Control-Allow-Credentials", "true")
        c.Header("Access-Control-Max-Age", "86400")

        // 处理预检请求
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }

        c.Next()
    }
}

严格的 CORS 配置

Go
func StrictCORSMiddleware(allowedOrigins []string) gin.HandlerFunc {
    return func(c *gin.Context) {
        origin := c.GetHeader("Origin")

        // 检查是否为允许的来源
        allowed := false
        for _, o := range allowedOrigins {
            if o == origin || o == "*" {
                allowed = true
                break
            }
        }

        if !allowed && origin != "" {
            c.AbortWithStatus(403)
            return
        }

        if allowed {
            c.Header("Access-Control-Allow-Origin", origin)
            c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
            c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")
            c.Header("Access-Control-Allow-Credentials", "true")
            c.Header("Access-Control-Max-Age", "3600")
        }

        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }

        c.Next()
    }
}

// 使用
r.Use(StrictCORSMiddleware([]string{
    "https://example.com",
    "https://admin.example.com",
}))

请求验证中间件

请求大小限制

Go
func RequestSizeLimitMiddleware(maxSize int64) gin.HandlerFunc {
    return func(c *gin.Context) {
        if c.Request.ContentLength > maxSize {
            c.JSON(413, gin.H{"error": "请求体过大"})
            c.Abort()
            return
        }

        // 限制实际读取大小
        c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxSize)

        c.Next()
    }
}

// 使用:限制请求体最大 1MB
r.Use(RequestSizeLimitMiddleware(1 << 20))

Content-Type 验证

Go
func ContentTypeMiddleware(allowedTypes []string) gin.HandlerFunc {
    return func(c *gin.Context) {
        if c.Request.Method == "GET" || c.Request.Method == "DELETE" {
            c.Next()
            return
        }

        contentType := c.GetHeader("Content-Type")
        valid := false

        for _, t := range allowedTypes {
            if strings.Contains(contentType, t) {
                valid = true
                break
            }
        }

        if !valid {
            c.JSON(415, gin.H{"error": "不支持的 Content-Type"})
            c.Abort()
            return
        }

        c.Next()
    }
}

// 使用:只允许 JSON
r.Use(ContentTypeMiddleware([]string{"application/json"}))

敏感信息过滤

响应信息清理

Go
func ResponseFilterMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 记录原始响应
        blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
        c.Writer = blw

        c.Next()

        // 过滤敏感字段(仅对 JSON 响应)
        if strings.Contains(c.Writer.Header().Get("Content-Type"), "application/json") {
            filtered := filterSensitiveFields(blw.body.String())
            c.Writer = gin.ResponseWriter(blw.original)
            c.Writer.Write([]byte(filtered))
        }
    }
}

type bodyLogWriter struct {
    body       *bytes.Buffer
    ResponseWriter gin.ResponseWriter
    original   gin.ResponseWriter
}

func filterSensitiveFields(jsonStr string) string {
    // 移除密码、token 等敏感字段
    sensitiveFields := []string{"password", "token", "secret", "api_key"}
    var data map[string]interface{}
    json.Unmarshal([]byte(jsonStr), &data)

    for _, field := range sensitiveFields {
        if _, exists := data[field]; exists {
            data[field] = "[FILTERED]"
        }
    }

    result, _ := json.Marshal(data)
    return string(result)
}

日志敏感信息过滤

Go
func SensitiveLogMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 记录请求(过滤敏感参数)
        logRequest(c)

        c.Next()

        // 记录响应
        logResponse(c)
    }
}

func logRequest(c *gin.Context) {
    params := c.Request.URL.Query()
    filteredParams := make(map[string]string)

    sensitiveKeys := []string{"password", "token", "key", "secret"}
    for k, v := range params {
        if isSensitiveKey(k, sensitiveKeys) {
            filteredParams[k] = "[FILTERED]"
        } else {
            filteredParams[k] = strings.Join(v, ",")
        }
    }

    log.Printf("Request: %s %s Params: %v", c.Request.Method, c.Request.URL.Path, filteredParams)
}

请求来源验证

IP 白名单

Go
func IPWhitelistMiddleware(allowedIPs []string) gin.HandlerFunc {
    allowedSet := make(map[string]bool)
    for _, ip := range allowedIPs {
        allowedSet[ip] = true
    }

    return func(c *gin.Context) {
        clientIP := c.ClientIP()

        if !allowedSet[clientIP] {
            c.JSON(403, gin.H{"error": "IP 不在白名单中"})
            c.Abort()
            return
        }

        c.Next()
    }
}

// 使用
r.Use(IPWhitelistMiddleware([]string{"127.0.0.1", "192.168.1.100"}))

Referer 验证

Go
func RefererCheckMiddleware(allowedReferers []string) gin.HandlerFunc {
    return func(c *gin.Context) {
        referer := c.GetHeader("Referer")

        // 对特定接口检查来源
        if strings.HasPrefix(c.Request.URL.Path, "/api/admin") {
            valid := false
            for _, r := range allowedReferers {
                if strings.HasPrefix(referer, r) {
                    valid = true
                    break
                }
            }

            if !valid {
                c.JSON(403, gin.H{"error": "非法请求来源"})
                c.Abort()
                return
            }
        }

        c.Next()
    }
}

综合安全中间件

Go
func FullSecurityMiddleware(config SecurityConfig) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 1. 请求大小检查
        if c.Request.ContentLength > config.MaxRequestSize {
            c.JSON(413, gin.H{"error": "请求过大"})
            c.Abort()
            return
        }

        // 2. IP 白名单检查
        if len(config.IPWhitelist) > 0 {
            ip := c.ClientIP()
            if !contains(config.IPWhitelist, ip) {
                c.JSON(403, gin.H{"error": "禁止访问"})
                c.Abort()
                return
            }
        }

        // 3. Content-Type 验证
        if c.Request.Method != "GET" && c.Request.Method != "DELETE" {
            ct := c.GetHeader("Content-Type")
            if !isValidContentType(ct, config.AllowedContentTypes) {
                c.JSON(415, gin.H{"error": "Content-Type 无效"})
                c.Abort()
                return
            }
        }

        // 4. 设置安全头部
        setSecurityHeaders(c)

        c.Next()
    }
}

type SecurityConfig struct {
    MaxRequestSize      int64
    IPWhitelist         []string
    AllowedContentTypes []string
    AllowedOrigins      []string
}

安全中间件配置示例

Go
func main() {
    r := gin.Default()

    // 安全配置
    config := SecurityConfig{
        MaxRequestSize:      2 << 20, // 2MB
        IPWhitelist:         []string{},
        AllowedContentTypes: []string{"application/json", "multipart/form-data"},
        AllowedOrigins:      []string{"https://example.com"},
    }

    // 应用安全中间件
    r.Use(FullSecurityMiddleware(config))
    r.Use(StrictCORSMiddleware(config.AllowedOrigins))
    r.Use(SecurityHeadersMiddleware())

    // 路由配置
    api := r.Group("/api")
    api.Use(JWTAuthMiddleware())
    {
        api.GET("/data", GetData)
    }

    r.Run(":8080")
}

安全头部说明

头部作用推荐值
X-XSS-ProtectionXSS 过滤1; mode=block
X-Content-Type-OptionsMIME 嗅探防护nosniff
X-Frame-Options点击劫持防护DENY
Strict-Transport-Security强制 HTTPSmax-age=31536000
Content-Security-Policy内容安全策略default-src 'self'

注意:CORS 配置需严格限制允许的来源,避免使用 * 允许所有域名。

要点总结

  1. 安全头部:设置 XSS、点击劫持、HTTPS 强制等防护头
  2. CORS 控制:严格限制允许的域名和方法
  3. 请求验证:限制大小、验证 Content-Type
  4. 敏感过滤:日志和响应中隐藏敏感信息
  5. 来源验证:IP 白名单、Referer 检查
  6. 综合配置:根据业务场景组合多个安全措施

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

← 上一篇 Gin XSS过滤
下一篇 → Gin 速率限制与防暴力破解
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

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

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