jwt解析必须显式校验exp/aud/iss,不能只依赖token.valid;须用jwt.parsewithclaims配合自定义keyfunc,强制调用claims.verifyexpiresat(..., true),比对预设aud/iss,拒绝alg为none,sub仅存用户id,权限查db,grpc需mtls双向验证,http出向防ssrf,容器非root运行。

JWT解析必须显式校验exp/aud/iss,不能只看token.Valid
很多Go服务用token.Valid判断JWT是否合法,但这是危险的——过期、伪造issuer或错配aud的token仍可能返回true。攻击者可重放旧token或篡改payload后重新签名(尤其HS256密钥泄露时)。
- 必须用
jwt.ParseWithClaims配合自定义Keyfunc,避免密钥硬编码 - 解析后强制调用
claims.VerifyExpiresAt(time.Now().Unix(), true),第二个参数不能为false - 显式比对
claims["aud"]和claims["iss"]是否匹配预设值(如"payment-service") - 检查
token.Header["alg"]是否为"HS256"或"RS256",直接拒绝"none" -
sub字段只放用户唯一ID,权限查DB或缓存,不塞进token
gRPC服务必须启用mTLS,且ClientAuth不能设成VerifyClientCertIfGiven
单向TLS只防窃听,不防伪造请求;tls.VerifyClientCertIfGiven允许客户端不提供证书,等于形同虚设。生产环境必须双向验证。
- 服务端
tls.Config.ClientAuth设为tls.RequireAndVerifyClientCert -
tls.Config.ClientCAs加载的是客户端证书的根CA证书池,不是客户端自己的证书 - 客户端
tls.Config.RootCAs加载服务端CA,Certificates加载自身完整证书链(含中间证书) - 在gRPC handler里用
peer.FromContext(ctx)拿到证书后,必须用x509.VerifyOptions校验签名,并检查Subject.Organization等字段是否可信
HTTP客户端调用下游时必须防SSRF,不能依赖K8s NetworkPolicy代替代码校验
URL来自用户输入(如webhook地址)时,http.DefaultClient直连会暴露内网。NetworkPolicy是网络层兜底,Go层才是第一道防线。
- 禁用
http.DefaultClient,所有出向client显式设置Transport - 自定义
DialContext:先net.ParseIP再用privateIP.IsPrivate()拒绝私有网段 - 对域名做真实DNS解析后校验IP,不能只看字符串是否含
.local - 上游传URL时限制协议为
https,禁止http、file、ftp等scheme
容器必须以非root用户运行,USER指令位置和UID写法有严格要求
Go二进制无依赖,一旦以root启动,内存越界就等于交出整个容器控制权。用gosu或su-exec runtime切用户无效——Go进程不fork。
-
Dockerfile中USER指令必须放在COPY之后、ENTRYPOINT之前 -
USER必须指定数字UID(如1001),不能写用户名(镜像里未必存在) - Kubernetes中需同时设置
securityContext.runAsUser: 1001和runAsNonRoot: true,否则Pod可能忽略镜像USER回退到root











