Validate or sanitize client-controlled inputs to the JwtBearer WWW-Authenticate header
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
When a JWT includes an invalid issuer or audience, the `JwtBearerHandler` will try to produce a `WWW-Authenticate` response header including the invalid issuer and/or audience from the user-supplied token.
These values appear to come from untrusted user input:
https://github.com/dotnet/aspnetcore/blob/27f2a011a4211118552dfb8f38d36e8629267d2b/src/Security/Authentication/JwtBearer/src/JwtBearerHandler.cs#L389-L390
And flow unescaped into headers here: https://github.com/dotnet/aspnetcore/blob/27f2a011a4211118552dfb8f38d36e8629267d2b/src/Security/Authentication/JwtBearer/src/JwtBearerHandler.cs#L328
This impact of this lack of validation in a response header is mitigated by the fact that our servers (Kestrel, IIS and HttpSys) ll immediately throw an InvalidOperationException from HttpResponse.Headers.Append as expected with a message indicating the header contained an invalid control character given any instance of either a carriage return or line feed in the header string.
All of our servers validate headers values when they are set using one of [these two methods](https://github.com/dotnet/aspnetcore/blob/257d69079e0f7fc84e3f6cd5047272d7f79b4d66/src/Shared/ServerInfrastructure/HttpCharacters.cs#L49-L54). The methods are SearchValues based, so it’s straightforward to see exactly which characters are allowed and disallowed if you’re interested. By default, Kestrel will only allow ASCII characters and IIS/HttpSys will allow extended ASCII, but none of our servers allow control characters regardless of how they’re configured.
Throwing an `InvalidOperationException` given a JWT token with an issuer or audience containing a newline isn’t ideal since this will usually result in a 500 response instead of a 401 response with a helpful `WWW-Authenticate` response header as expected. The simplest option to fix this would be to always use a generic error_description for invalid issuers and audiences, but I think that would be unnecessarily inconvenient in development scenarios. I would probably scan the InvalidIssuer and InvalidAudience to verify it only has allowed characters before using it in the error_description and fall back to a generic message otherwise.
Contributor guide
Assessment
This issue has not been assessed yet.