




Golang微服务安全需从认证、通信、存储、运行时四层设防:JWT须校验exp/iat/alg/aud/iss且禁用none算法;TLS须强制1.2+并白名单密套;敏感数据须AES-GCM加密且密钥不硬编;容器须非root只读运行。
Golang微服务安全加固不是加一层“防护罩”就完事,而是从认证、通信、存储、运行时四个层面主动设防。不这么做,JWT可能被重放、TLS配置可能降级、敏感字段可能进日志、容器可能以root跑满权限——漏洞不在代码里,而在这些默认没关的口子上。
golang-jwt/jwt/v5 做认证,但别只校验签名token.Valid 就放行,漏掉关键声明校验。比如攻击者截获一个过期但签名有效的 token,服务端若不检查 exp 和 iat,就会误判为有效。
必须显式验证:token.Claims.(jwt.MapClaims)["exp"] 要转成 int64 后与 time.Now().Unix() 比较token.Header["alg"] 需限定为 "RS256" 或 "HS256",拒绝 "none" 算法token.Claims.(jwt.MapClaims)["aud"] 和 "iss" 要匹配预设值(如 "api.example.com"),防跨服务伪造
别把用户密码、手机号塞进 payload:JWT 是 Base64Url 编码,非加密,仅用于身份标识
refresh token 必须存服务端(如 Redis),绑定设备指纹和 IP,且单次使用后立即失效
func verifyToken(tokenString string) (*jwt.Token, error) {
keyFunc := func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
}
return publicKey, nil
}
token, err := jwt.Parse(tokenString, keyFunc)
if err != nil || !token.Valid {
return nil, errors.New("invalid token")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !claims.VerifyExpiresAt(time.Now().Unix(), true) ||
claims["aud"] != "backend-api" || claims["iss"] != "auth-service" {
return nil, errors.New("token claim validation failed")
}
return token, nil
}TLS 1.2+ 并禁用弱密码套件,否则 HTTPS 形同虚设ListenAndServeTLS 就以为安全了,但若没限制协议版本和加密套件,中间人仍可协商 TLS 1.0 + RC4,轻松解密流量。
tls.Config 中必须设置:MinVersion: tls.VersionTLS12(禁用 TLS 1.0/1.1)CipherSuites: []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, ...}(显式白名单,不依赖 Go 默认)PreferServerCipherSuites: true(让服务端决定,而非客户端诱导)
自签名证书仅限测试;生产务必用 Let’s Encrypt 或私有 CA,并在客户端校验 RootCAs
若用 mTLS,服务端需设 ClientAuth: tls.RequireAndVerifyClientCert,且客户端证书必须带 SAN 扩展
AES-GCM 加密,别信 ORM 的“自动加密”crypto/aes + crypto/cipher.NewGCM,每次加密生成随机 nonce(12 字节)并拼接在密文前 []byte 持有,避免字符串常量被内存 dump 抓取 readOnlyRootFilesystem,否则一次 RCE 就等于宿主机沦陷root 启动,又没限制能力,攻击者通过任意文件写入(如日志目录)就能逃逸到宿主机。
RUN adduser -u 1001 -D appuserUSER appuser securityContext.runAsNonRoot: truesecurityContext.runAsUser: 1001securityContext.readOnlyRootFilesystem: truesecurityContext.capabilities.drop: ["ALL"] /proc、/sys、/dev 等宿主机路径,除非明确需要 真正难的不是写对某段加密代码,而是所有环节都保持防御纵深:JWT 校验不漏字段、TLS 不降级、密钥不落地、进程不越权。任何一个环节松动,整条链就断了。