|  | 
| 8 | 8 | 	"strings" | 
| 9 | 9 | ) | 
| 10 | 10 | 
 | 
|  | 11 | +const tokenDelimiter = "." | 
|  | 12 | + | 
| 11 | 13 | type Parser struct { | 
| 12 | 14 | 	// If populated, only these methods will be considered valid. | 
| 13 | 15 | 	validMethods []string | 
| @@ -136,9 +138,10 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf | 
| 136 | 138 | // It's only ever useful in cases where you know the signature is valid (since it has already | 
| 137 | 139 | // been or will be checked elsewhere in the stack) and you want to extract values from it. | 
| 138 | 140 | func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) { | 
| 139 |  | -	parts = strings.Split(tokenString, ".") | 
| 140 |  | -	if len(parts) != 3 { | 
| 141 |  | -		return nil, parts, newError("token contains an invalid number of segments", ErrTokenMalformed) | 
|  | 141 | +	var ok bool | 
|  | 142 | +	parts, ok = splitToken(tokenString) | 
|  | 143 | +	if !ok { | 
|  | 144 | +		return nil, nil, newError("token contains an invalid number of segments", ErrTokenMalformed) | 
| 142 | 145 | 	} | 
| 143 | 146 | 
 | 
| 144 | 147 | 	token = &Token{Raw: tokenString} | 
| @@ -196,6 +199,33 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke | 
| 196 | 199 | 	return token, parts, nil | 
| 197 | 200 | } | 
| 198 | 201 | 
 | 
|  | 202 | +// splitToken splits a token string into three parts: header, claims, and signature. It will only | 
|  | 203 | +// return true if the token contains exactly two delimiters and three parts. In all other cases, it | 
|  | 204 | +// will return nil parts and false. | 
|  | 205 | +func splitToken(token string) ([]string, bool) { | 
|  | 206 | +	parts := make([]string, 3) | 
|  | 207 | +	header, remain, ok := strings.Cut(token, tokenDelimiter) | 
|  | 208 | +	if !ok { | 
|  | 209 | +		return nil, false | 
|  | 210 | +	} | 
|  | 211 | +	parts[0] = header | 
|  | 212 | +	claims, remain, ok := strings.Cut(remain, tokenDelimiter) | 
|  | 213 | +	if !ok { | 
|  | 214 | +		return nil, false | 
|  | 215 | +	} | 
|  | 216 | +	parts[1] = claims | 
|  | 217 | +	// One more cut to ensure the signature is the last part of the token and there are no more | 
|  | 218 | +	// delimiters. This avoids an issue where malicious input could contain additional delimiters | 
|  | 219 | +	// causing unecessary overhead parsing tokens. | 
|  | 220 | +	signature, _, unexpected := strings.Cut(remain, tokenDelimiter) | 
|  | 221 | +	if unexpected { | 
|  | 222 | +		return nil, false | 
|  | 223 | +	} | 
|  | 224 | +	parts[2] = signature | 
|  | 225 | + | 
|  | 226 | +	return parts, true | 
|  | 227 | +} | 
|  | 228 | + | 
| 199 | 229 | // DecodeSegment decodes a JWT specific base64url encoding. This function will | 
| 200 | 230 | // take into account whether the [Parser] is configured with additional options, | 
| 201 | 231 | // such as [WithStrictDecoding] or [WithPaddingAllowed]. | 
|  | 
0 commit comments