Golang中验证无kid字段的JWT令牌问题咨询
验证无kid字段的JWT令牌(golang-jwt/jwt/v4)
你遇到的错误是因为使用的jwks.Keyfunc默认依赖JWT Header中的kid字段去JWKS集合匹配公钥,但你的JWT Header没有该字段,导致匹配失败。
核心解决思路是自定义jwt.Keyfunc函数,根据实际场景处理无kid的情况:
场景1:第三方JWKS仅包含一个RS256公钥
如果确定JWKS里只有一个用于RS256签名的公钥,直接用该公钥验证即可:
import ( "fmt" "github.com/golang-jwt/jwt/v4" "crypto/rsa" ) // 假设已通过JWKS端点或其他方式获取到公钥pubKey(*rsa.PublicKey类型) tokenParsed, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { // 先校验签名算法是否符合预期 if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } // 返回预获取的公钥 return pubKey, nil }) if err != nil { ch.Log(alog.FATAL, "Failed to parse the JWT.\nError: %s", err.Error()) }
场景2:JWKS包含多个密钥,无kid时使用默认密钥
如果JWKS有多个密钥,且第三方约定无kid时使用默认密钥(比如第一个RS256密钥),可以在Keyfunc中添加无kid的处理逻辑:
import ( "fmt" "github.com/golang-jwt/jwt/v4" "github.com/lestrrat-go/jwx/jwks" ) // 假设已加载JWKS密钥集jwksSet tokenParsed, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { // 校验签名算法 if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } // 尝试获取kid字段 kid, ok := token.Header["kid"].(string) if !ok { // 无kid时,查找JWKS中第一个RS256类型的密钥 for _, key := range jwksSet.Keys() { if key.Algorithm() == "RS256" { pubKey, err := key.PublicKey() if err != nil { return nil, err } return pubKey, nil } } return nil, fmt.Errorf("no default RS256 key found in JWKS") } // 有kid时按原逻辑查找密钥 key, ok := jwksSet.LookupKeyID(kid) if !ok { return nil, fmt.Errorf("key with kid %s not found", kid) } pubKey, err := key.PublicKey() if err != nil { return nil, err } return pubKey, nil }) if err != nil { ch.Log(alog.FATAL, "Failed to parse the JWT.\nError: %s", err.Error()) }
关键要点
- 不要直接使用
jwks.Keyfunc,而是自己实现jwt.Keyfunc,灵活处理无kid的场景 - 必须先校验签名算法,避免算法绕过攻击
内容的提问来源于stack exchange,提问作者Shihabudheen K M
相关产品推荐
相关产品推荐

