Go Web 编程实战Go Web 编程实战
首页
课程导读
首页
课程导读
  • 课程导读
  • 课程目录

    • Go基础语法精要
    • Web基础与HTTP处理
    • Gin框架入门
    • 路由与中间件
    • 数据库操作
    • 模板渲染
    • 错误处理与日志
    • 测试与部署
    • 高级中间件模式
    • 微服务架构
    • 性能优化
    • 安全最佳实践
    • 项目结构与代码组织

安全最佳实践

1. 常见Web安全威胁

威胁描述防护措施
SQL注入通过输入恶意SQL破坏数据库参数化查询
XSS注入客户端脚本攻击其他用户输出编码,CSP
CSRF利用用户身份执行非预期操作CSRF令牌,SameSite Cookie
会话劫持窃取会话标识冒充用户安全Cookie属性,HTTPS
信息泄露暴露敏感数据或系统信息错误处理,最小化响应

2. 输入验证与过滤

使用validator库验证输入

import "github.com/go-playground/validator/v10"

type UserInput struct {
    Username string `validate:"required,alphanum,min=4,max=20"`
    Email    string `validate:"required,email"`
    Age      int    `validate:"min=18"`
}

func validateInput(input UserInput) error {
    validate := validator.New()
    if err := validate.Struct(input); err != nil {
        return err
    }
    return nil
}

防范SQL注入

// 错误的做法(易受SQL注入)
query := fmt.Sprintf("SELECT * FROM users WHERE username = '%s'", username)
rows, err := db.Query(query)

// 正确的做法(参数化查询)
rows, err := db.Query("SELECT * FROM users WHERE username = ?", username)

HTML净化

import "github.com/microcosm-cc/bluemonday"

func sanitizeHTML(input string) string {
    p := bluemonday.UGCPolicy()
    return p.Sanitize(input)
}

3. 认证与授权

安全的密码存储

import "golang.org/x/crypto/bcrypt"

// 密码哈希
func hashPassword(password string) (string, error) {
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    return string(bytes), err
}

// 密码验证
func checkPassword(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

JWT认证实现

import "github.com/dgrijalva/jwt-go"

func createToken(userID string, secret []byte) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "user_id": userID,
        "exp":     time.Now().Add(time.Hour * 24).Unix(),
    })
    return token.SignedString(secret)
}

func validateToken(tokenString string, secret []byte) (string, error) {
    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("Unexpected signing method")
        }
        return secret, nil
    })
    
    if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
        return claims["user_id"].(string), nil
    }
    return "", err
}

4. 安全传输与存储

HTTPS配置

import (
    "crypto/tls"
    "net/http"
)

func startSecureServer() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Secure Connection"))
    })
    
    cfg := &tls.Config{
        MinVersion:               tls.VersionTLS12,
        CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
        PreferServerCipherSuites: true,
        CipherSuites: []uint16{
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
        },
    }
    
    srv := &http.Server{
        Addr:         ":443",
        Handler:      mux,
        TLSConfig:    cfg,
        TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
    }
    
    log.Fatal(srv.ListenAndServeTLS("cert.pem", "key.pem"))
}

安全Cookie设置

func setSecureCookie(w http.ResponseWriter, name, value string) {
    http.SetCookie(w, &http.Cookie{
        Name:     name,
        Value:    value,
        Path:     "/",
        MaxAge:   3600,
        HttpOnly: true,
        Secure:   true,
        SameSite: http.SameSiteStrictMode,
    })
}

5. 安全头设置

使用Gin中间件设置安全头

func SecurityHeaders() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 防止MIME类型嗅探
        c.Header("X-Content-Type-Options", "nosniff")
        // 防止点击劫持
        c.Header("X-Frame-Options", "DENY")
        // XSS保护
        c.Header("X-XSS-Protection", "1; mode=block")
        // 内容安全策略
        c.Header("Content-Security-Policy", "default-src 'self'")
        // 推荐使用HTTPS
        c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
        
        c.Next()
    }
}

func main() {
    r := gin.Default()
    r.Use(SecurityHeaders())
    // ...路由设置
    r.Run(":8080")
}

CORS安全配置

func CORSMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        origin := c.Request.Header.Get("Origin")
        allowedOrigins := []string{
            "https://example.com",
            "https://api.example.com",
        }
        
        for _, o := range allowedOrigins {
            if o == origin {
                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")
                c.Header("Access-Control-Allow-Credentials", "true")
                c.Header("Access-Control-Max-Age", "86400")
                
                if c.Request.Method == "OPTIONS" {
                    c.AbortWithStatus(204)
                    return
                }
                break
            }
        }
        
        c.Next()
    }
}

提示:安全是一个持续的过程,不是一次性任务。保持依赖项更新,定期进行安全审计,并遵循最小权限原则。

Prev
性能优化
Next
项目结构与代码组织