Skip to main content

Business information leak - Token

Need

Protection of sensitive user information in session tokens

Context

  • Usage of C# 7.1 for developing applications with advanced language features and improvements
  • Usage of Microsoft.AspNetCore.Mvc for building web applications with ASP.NET Core
  • Usage of Microsoft.AspNetCore.Identity for managing user authentication and authorization in ASP.NET Core applications
  • Usage of Microsoft.AspNetCore.Authentication.Cookies for handling cookie-based authentication in ASP.NET Core applications

Description

Non compliant code

public async Task<IActionResult> Login(UserLoginModel model)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Email, user.Email),
new Claim("FullName", user.FullName)
};

var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

return RedirectToAction("Index", "Home");
}

return View();
}

The above code is an example of a Login method in an ASP.NET Core application. The method takes a UserLoginModel as a parameter which contains the email and password of the user trying to log in.

The method first finds the user by their email using the _userManager.FindByEmailAsync(model.Email) method. If the user exists and the password is correct, it creates a list of claims which includes the user's username, email, and full name. These claims are then used to create a ClaimsIdentity which is used to create a ClaimsPrincipal.

The ClaimsPrincipal is then signed in using HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal). This results in a session token being created which contains the user's username, email, and full name. This session token is then sent to the client where it can be potentially intercepted and the user's information leaked.

The vulnerability here is that sensitive user information (username, email, and full name) is included in the session token. If an attacker can get hold of this token, they can extract this information and use it for malicious purposes.

Steps

  • Do not include sensitive information in the session token.
  • Avoid storing user-specific information in the session token.
  • Use separate mechanisms to store and retrieve user information, such as a database or cache.
  • Instead of including sensitive information in the session token, store a unique identifier (e.g., user ID) and retrieve the necessary information from a secure data source when needed.
  • Ensure that the session token is securely encrypted and protected from unauthorized access.
  • Regularly review and update the token generation and handling process to address any potential vulnerabilities.

Compliant code

public async Task<IActionResult> Login(UserLoginModel model)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString())
};

var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

return RedirectToAction("Index", "Home");
}

return View();
}

The updated code no longer includes sensitive user information in the session token. Instead, it only includes a unique identifier for the user (in this case, the user's ID). This ID can then be used to retrieve the necessary user information from a secure data source when needed.

The ClaimTypes.NameIdentifier is used to store the user's ID. This is a standard claim type defined by the .NET framework, which is intended to hold a unique identifier for the user.

The HttpContext.SignInAsync method is used to sign the user in. This method creates a session for the user and stores the session token in a cookie. The session token includes the claims defined in the ClaimsIdentity object.

By only including the user's ID in the session token, we avoid exposing sensitive user information in case the session token is compromised. Furthermore, by using the SignInAsync method to handle session creation and management, we ensure that the session token is securely encrypted and protected from unauthorized access.

It's important to regularly review and update the token generation and handling process to address any potential vulnerabilities. This includes ensuring that the session token is securely transmitted (e.g., over HTTPS), and that it is properly invalidated when the user logs out or after a certain period of inactivity.

References