C
C#2y ago
S-IERRA

❔ ASP.NET always validates invalid JWT

I have a custom configuration for Asp.net where the JWT Token is stored in an http-only cookie, because of this there is 1 method in specific that is always returning 200 no matter if there is no actual JWT attached
public static void RegisterAuthorization(this IServiceCollection serviceCollection, IConfiguration configuration)
{
var jwtConfig = configuration.GetSection("Jwt").Get<JwtConfig>()!;
serviceCollection.Configure<JwtConfig>(configuration.GetSection("Jwt"));

serviceCollection.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = jwtConfig.Audience,
ValidIssuer = jwtConfig.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.Key))
};

options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
context.Token = context.Request.Cookies["JwtToken"];

return Task.CompletedTask;
}
};
});

serviceCollection.AddAuthorization(options =>
{
options.AddPolicy(NumixAuthPolicy.Admin.ToString(), policy =>
policy.RequireClaim(ClaimTypes.Role, NumixRole.Administrator.ToString()));
});

serviceCollection.AddScoped(typeof(IAuthenticatorService), typeof(Authenticate));
}
public static void RegisterAuthorization(this IServiceCollection serviceCollection, IConfiguration configuration)
{
var jwtConfig = configuration.GetSection("Jwt").Get<JwtConfig>()!;
serviceCollection.Configure<JwtConfig>(configuration.GetSection("Jwt"));

serviceCollection.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = jwtConfig.Audience,
ValidIssuer = jwtConfig.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.Key))
};

options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
context.Token = context.Request.Cookies["JwtToken"];

return Task.CompletedTask;
}
};
});

serviceCollection.AddAuthorization(options =>
{
options.AddPolicy(NumixAuthPolicy.Admin.ToString(), policy =>
policy.RequireClaim(ClaimTypes.Role, NumixRole.Administrator.ToString()));
});

serviceCollection.AddScoped(typeof(IAuthenticatorService), typeof(Authenticate));
}
57 Replies
S-IERRA
S-IERRAOP2y ago
When a different jwt token requests data of a diferent id it returns an empty array but 200
[Authorize]
[HttpPost("fetch-transactions")]
[ProducesResponseType(200)]
[ProducesResponseType(401)]
public async Task<IActionResult> FetchTransactions([FromClaim(NumixClaims.NumixId)] Guid numixId)
{
DateTimeOffset now = DateTimeOffset.UtcNow.AddYears(-10);
List<BasicNumixTransaction> completedTransactions = await _saleAnalytics.FetchDbTransactions(startDate: now, paymentStatus: PaymentStatus.Success, userId: numixId);

return Ok(JsonSerializer.Serialize(completedTransactions, JsonHelper.JsonSerializerOptions));
}
[Authorize]
[HttpPost("fetch-transactions")]
[ProducesResponseType(200)]
[ProducesResponseType(401)]
public async Task<IActionResult> FetchTransactions([FromClaim(NumixClaims.NumixId)] Guid numixId)
{
DateTimeOffset now = DateTimeOffset.UtcNow.AddYears(-10);
List<BasicNumixTransaction> completedTransactions = await _saleAnalytics.FetchDbTransactions(startDate: now, paymentStatus: PaymentStatus.Success, userId: numixId);

return Ok(JsonSerializer.Serialize(completedTransactions, JsonHelper.JsonSerializerOptions));
}
Florian Voß
Florian Voß2y ago
are you sure it returns 200 even with no JWT? shouldn't be possible 🤔 . I assume you still had a JWT stored somewhere that authenticated you, is that possible? How about using expiration on the JWT? accept JWT only for 24 hours or smth and include check for expiration date in your policy maybe
S-IERRA
S-IERRAOP2y ago
Yes, let me show you
Florian Voß
Florian Voß2y ago
not sure how you would show this to me. What exactly does options.Save = true mean? where does it save the JWT?
S-IERRA
S-IERRAOP2y ago
so its fetched from a cookie which is currently set
S-IERRA
S-IERRAOP2y ago
also sure just a sec
S-IERRA
S-IERRAOP2y ago
I remove the cookie / log out and seems to still be allowing it
S-IERRA
S-IERRAOP2y ago
it doesnt really allowt o fetch other ids but
S-IERRA
S-IERRAOP2y ago
Possibly like you said this
S-IERRA
S-IERRAOP2y ago
let me check
S-IERRA
S-IERRAOP2y ago
Florian Voß
Florian Voß2y ago
I guess a JWT might have been saved there from your last auth
S-IERRA
S-IERRAOP2y ago
just a sec cuz i gotta remeber the passoword
S-IERRA
S-IERRAOP2y ago
no still no
S-IERRA
S-IERRAOP2y ago
S-IERRA
S-IERRAOP2y ago
S-IERRA
S-IERRAOP2y ago
both are 200s
Florian Voß
Florian Voß2y ago
Not sure if this will help us find out but when you go in browser into dev tools where you use swagger onto Application, can you find a JWT token in cookies there? Not sure what name the cookie would have, any cookie value that starts with "ey..."?
S-IERRA
S-IERRAOP2y ago
S-IERRA
S-IERRAOP2y ago
im thinking could it be because of this
S-IERRA
S-IERRAOP2y ago
S-IERRA
S-IERRAOP2y ago
S-IERRA
S-IERRAOP2y ago
i mean its old and wont work now anyway but im thinking now it could be smthn to do with one of my middlewares but i dont think thats the case weird because it seems like its skipping over auth completly for this specific method
Florian Voß
Florian Voß2y ago
this seems to add the Token to request in Swagger I would guess this request here contains a token this one does not
S-IERRA
S-IERRAOP2y ago
yes thats before log out yes
S-IERRA
S-IERRAOP2y ago
S-IERRA
S-IERRAOP2y ago
for some reason its skipping authorization
Florian Voß
Florian Voß2y ago
have you tried adding the name of your auth policy on the attribute? it should apply it anyway but I'm not sure
S-IERRA
S-IERRAOP2y ago
that auth policy breaks everything and puts everything on 403 so i dont use it anymore
Florian Voß
Florian Voß2y ago
then the one you'd like to be using
S-IERRA
S-IERRAOP2y ago
thats the thing there isnt any policy
Florian Voß
Florian Voß2y ago
in the middleware you have shown to me there was 🤷‍♂️
S-IERRA
S-IERRAOP2y ago
let me check that could be why oh this
S-IERRA
S-IERRAOP2y ago
S-IERRA
S-IERRAOP2y ago
its not used anywhere i just removed it
Florian Voß
Florian Voß2y ago
yep okay
S-IERRA
S-IERRAOP2y ago
seems like a bug within asp but im not sure
Florian Voß
Florian Voß2y ago
very unlikely more likely that you and me are both being harold
S-IERRA
S-IERRAOP2y ago
probably
Kouhai
Kouhai2y ago
Do you have AllowAnonymous on your controller? @S-IERRA
S-IERRA
S-IERRAOP2y ago
yes
S-IERRA
S-IERRAOP2y ago
S-IERRA
S-IERRAOP2y ago
but shouldnt authorise on the method its self over write this?
Kouhai
Kouhai2y ago
No, it's the other way around afaik
S-IERRA
S-IERRAOP2y ago
I ll try unlinking that allow anonymous on all other methods Inlining
Kouhai
Kouhai2y ago
You don't need to inline it
S-IERRA
S-IERRAOP2y ago
and remove it from the class
Kouhai
Kouhai2y ago
As long as the controller doesn't have Authorize it will allow Anonymouse accsess by default
S-IERRA
S-IERRAOP2y ago
im thinking for some reason allow anounymous is over writing that access controller below which wouldnt make sense but it could be ok that was indeed the case i assume this is a ASP.NET bug possibly someone from asp.net team could investigate?
Kouhai
Kouhai2y ago
I don't think it's a bug tbh
S-IERRA
S-IERRAOP2y ago
i mean allow anon on class shouldnt over write authorize on method
SinFluxx
SinFluxx2y ago
Kouhai
Kouhai2y ago
^
S-IERRA
S-IERRAOP2y ago
oh shit alright thanks thats good to know
SinFluxx
SinFluxx2y ago
It seems a more likely scenario you'd have Authorize on your controller and AllowAnonymous on a specific method
S-IERRA
S-IERRAOP2y ago
yes i see now thanks
Accord
Accord17mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.

Did you find this page helpful?