JWT Signature Verification Bypass
ID |
csharp.jwt_signature_verification_bypass |
Severity |
high |
Resource |
Cryptography |
Language |
CSharp |
Tags |
CWE:347, NIST.SP.800-53, OWASP:2021:A3, OWASP:2021:A7, PCI-DSS:6.5.10, PCI-DSS:6.5.6, PCI-DSS:6.5.8 |
Rationale
JWT signature verification bypass refers to a scenario where a JSON Web Token, designed to be a secure way to transmit information between parties, is not properly checked for a valid signature.
This can allow attackers to forge tokens, gaining unauthorized access to protected resources or services.
In C#, JWT handling is often done using libraries like System.IdentityModel.Tokens.Jwt
, jose-jwt
or Microsoft.AspNetCore.Authentication.JwtBearer
. For example, consider the following sample code using the JwtBearer
library:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System.Text;
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = false, // VULNERABLE !
ValidIssuer = "your_issuer",
ValidAudience = "your_audience"
};
});
// Other configurations...
}
In the example above, the signature is not verified. An attacker may forge any JWT token that, if the other checks pass, will allow the token to be accepted as valid authentication token for the ASP.NET application.
Another option using ASP.NET Core Microsoft.IdentityModel
library:
using System;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
public SecurityToken ValidateToken(string token)
{
var options = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateIssuerSigningKey = false, // VULNERABLE !
RequireSignedTokens = false,
SignatureValidator = (token, parameters) => new JwtSecurityToken(token),
ValidateLifetime = false
};
var tokenHandler = new JwtSecurityTokenHandler();
SecurityToken validatedToken;
tokenHandler.ValidateToken(token, options, out var validatedToken);
return validatedToken;
}
Remediation
To remediate the JWT signature verification bypass, ensure that you are properly configuring the JWT parser in use, and always verifying the token signature with a trusted public key or secret.
Furthermore, make sure your JWT libraries are updated to the latest versions, which often address security vulnerabilities and provide enhanced capabilities. Additionally, it’s important to apply similar best practices across all environments where JWTs are used or processed to maintain consistent security assurances.
Here’s how you can correctly verify a JWT signature using the JwtBearer
library:
// ... rest of the code is the same
var options = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateIssuerSigningKey = true, // FIXED
RequireSignedTokens = false,
// do not mess with SignatureValidator
ValidateLifetime = false
};
Now signatures (HMAC-based) in JWT tokens are checked by the library, with the given key. Without the key, attackers will not be able to forge valid JWT tokens to impersonate a user with a valid token.
Remember that key handling is the weakest link in cryptography. Never hardcode keys in code. One alternative is to use public key cryptography, where the public key needed for signature validation does not need to be kept secret. |
For the second example, here’s how you can correctly verify a JWT signature using the Microsoft.IdentityModel
library:
// ... rest of the code is the same
options.ValidateIssuer = false;
options.ValidateAudience = false;
options.ValidateLifetime = false;
options.ValidateIssuerSigningKey = true; // FIXED
// ...
References
-
CWE-347 : Improper Verification of Cryptographic Signature