Securely generate session tokens with shorter expiration times
public class TokenController : Controller
{
private readonly IConfiguration _config;
public TokenController(IConfiguration config)
{
_config = config;
}
[HttpPost]
public IActionResult CreateToken([FromBody] LoginModel login)
{
IActionResult response = Unauthorized();
var user = AuthenticateUser(login);
if (user != null)
{
var tokenString = GenerateJSONWebToken(user);
response = Ok(new { token = tokenString });
}
return response;
}
private string GenerateJSONWebToken(UserModel userInfo)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Issuer"],
null,
expires: DateTime.Now.AddDays(5),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
The vulnerable code above is a controller in an ASP.NET Core application that generates a JWT (JSON Web Token) for authenticated users. The
GenerateJSONWebToken
method is responsible for creating the token.
The vulnerability lies in the
expires: DateTime.Now.AddDays(5)
line of code. This sets the expiration of the token to be 5 days from the current time. This is a security risk because if an attacker gets hold of the token, they can use it to impersonate the user for up to 5 days.
If the token is stolen, the user's data can be compromised for a significant period of time, allowing the attacker to perform unauthorized actions. This is especially risky if the application doesn't have any mechanism to invalidate the token before it naturally expires.
The best practice is to have a short lifespan for tokens and provide a refresh token mechanism for when the token needs to be renewed. This way, in case a token is compromised, the time window for potential malicious activities is significantly reduced.
public class TokenController : Controller
{
private readonly IConfiguration _config;
public TokenController(IConfiguration config)
{
_config = config;
}
[HttpPost]
public IActionResult CreateToken([FromBody] LoginModel login)
{
IActionResult response = Unauthorized();
var user = AuthenticateUser(login);
if (user != null)
{
var tokenString = GenerateJSONWebToken(user);
response = Ok(new { token = tokenString });
}
return response;
}
private string GenerateJSONWebToken(UserModel userInfo)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Issuer"],
null,
expires: DateTime.Now.AddHours(1), // Token lifespan reduced to 1 hour
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
The original code was generating JSON Web Tokens (JWT) with a lifespan of 5 days. This is a security vulnerability as it allows for a longer window of opportunity for an attacker to use a stolen token.
The fixed code reduces the lifespan of the JWT to 1 hour. This significantly reduces the potential damage of a token theft, as the token would only be valid for a short period of time.
In addition to reducing the token lifespan, it is recommended to use a more secure algorithm for generating the tokens, implement a token revocation mechanism to invalidate tokens before their expiration, securely store the token expiration time and validate it on each request, and consider implementing a token refresh mechanism to allow users to obtain new tokens without re-authenticating.