|
7 | 7 | "strings"
|
8 | 8 | )
|
9 | 9 |
|
| 10 | +const tokenDelimiter = "." |
| 11 | + |
10 | 12 | type Parser struct {
|
11 | 13 | // If populated, only these methods will be considered valid.
|
12 | 14 | //
|
@@ -122,9 +124,10 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
|
122 | 124 | // It's only ever useful in cases where you know the signature is valid (because it has
|
123 | 125 | // been checked previously in the stack) and you want to extract values from it.
|
124 | 126 | func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
|
125 |
| - parts = strings.Split(tokenString, ".") |
126 |
| - if len(parts) != 3 { |
127 |
| - return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed) |
| 127 | + var ok bool |
| 128 | + parts, ok = splitToken(tokenString) |
| 129 | + if !ok { |
| 130 | + return nil, nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed) |
128 | 131 | }
|
129 | 132 |
|
130 | 133 | token = &Token{Raw: tokenString}
|
@@ -174,3 +177,30 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
|
174 | 177 |
|
175 | 178 | return token, parts, nil
|
176 | 179 | }
|
| 180 | + |
| 181 | +// splitToken splits a token string into three parts: header, claims, and signature. It will only |
| 182 | +// return true if the token contains exactly two delimiters and three parts. In all other cases, it |
| 183 | +// will return nil parts and false. |
| 184 | +func splitToken(token string) ([]string, bool) { |
| 185 | + parts := make([]string, 3) |
| 186 | + header, remain, ok := strings.Cut(token, tokenDelimiter) |
| 187 | + if !ok { |
| 188 | + return nil, false |
| 189 | + } |
| 190 | + parts[0] = header |
| 191 | + claims, remain, ok := strings.Cut(remain, tokenDelimiter) |
| 192 | + if !ok { |
| 193 | + return nil, false |
| 194 | + } |
| 195 | + parts[1] = claims |
| 196 | + // One more cut to ensure the signature is the last part of the token and there are no more |
| 197 | + // delimiters. This avoids an issue where malicious input could contain additional delimiters |
| 198 | + // causing unecessary overhead parsing tokens. |
| 199 | + signature, _, unexpected := strings.Cut(remain, tokenDelimiter) |
| 200 | + if unexpected { |
| 201 | + return nil, false |
| 202 | + } |
| 203 | + parts[2] = signature |
| 204 | + |
| 205 | + return parts, true |
| 206 | +} |
0 commit comments