Description
Splitting a JWT yourself or reading it with a decode-only API such as ReadJwtToken does not verify its signature. Trusting the resulting claims for authentication or authorization can allow attacker-forged values to be used.
Potential impact
- Authentication bypass, privilege escalation, and user impersonation.
Remediation
Use JwtSecurityTokenHandler.ValidateToken or ASP.NET Core authentication middleware to validate the signature, issuer, audience, and expiry time.
Examples
Before
csharp
sealed class Jwt
{
public string[] Decode(JwtValidationRequest request)
{
return request.Token.Split('.');
}
}
sealed class JwtValidationRequest
{
public string Token { get; set; } = "";
}
After
Provide the key from trusted configuration and set the issuer and audience to the actual service values. Treat validation failure as authentication failure.
csharp
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
ClaimsPrincipal ValidateJwt(string token, SecurityKey trustedSigningKey)
{
var validationParameters = new TokenValidationParameters
{
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = trustedSigningKey,
ValidAlgorithms = new[] { SecurityAlgorithms.RsaSha256 },
ValidateIssuer = true,
ValidIssuer = "https://issuer.example.com",
ValidateAudience = true,
ValidAudience = "api://orders",
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(1)
};
return new JwtSecurityTokenHandler().ValidateToken(
token, validationParameters, out _);
}
Explanation:
- Before: Splitting a string is not validation. Trusting claims from an unvalidated token can admit forged or unsigned values.
- After: Fix the trusted key and permitted algorithm, and validate the signature, issuer, audience, and expiry time. Adding a
ValidateTokencall while weakening its validation options is not safe.