All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.csharp.S6781.html Maven / Gradle / Ivy

There is a newer version: 10.2.0.105762
Show newest version

Secret leaks often occur when a sensitive piece of authentication data is stored with the source code of an application. Considering the source code is intended to be deployed across multiple assets, including source code repositories or application hosting servers, the secrets might get exposed to an unintended audience.

Why is this an issue?

In most cases, trust boundaries are violated when a secret is exposed in a source code repository or an uncontrolled deployment environment. Unintended people who don’t need to know the secret might get access to it. They might then be able to use it to gain unwanted access to associated services or resources.

The trust issue can be more or less severe depending on the people’s role and entitlement.

What is the potential impact?

If a JWT secret key leaks to an unintended audience, it can have serious security implications for the corresponding application. The secret key is used to encode and decode JWTs when using a symmetric signing algorithm, and an attacker could potentially use it to perform malicious actions.

For example, an attacker could use the secret key to create their own authentication tokens that appear to be legitimate, allowing them to bypass authentication and gain access to sensitive data or functionality.

In the worst-case scenario, an attacker could be able to execute arbitrary code on the application by abusing administrative features, and take over its hosting server.

How to fix it in ASP.NET Core

Code examples

Noncompliant code example

Secrets stored in appsettings.json can be read by anyone with access to the file.

[ApiController]
[Route("login-example")]
public class LoginExampleController : ControllerBase
{
    private readonly IConfiguration _config;
    public LoginExampleController(IConfiguration config)
    {
        _config = config;
    }

    [HttpPost]
    public IActionResult Post([FromBody] LoginModel login)
    {
        // Code to validate the login information is omitted

        var key = _config["Jwt:Key"] ??
            throw new ApplicationException("JWT key is not configured.");
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)); // Noncompliant
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var Sectoken = new JwtSecurityToken(
            "example.com",
            "example.com",
            null,
            expires: DateTime.Now.AddMinutes(120),
            signingCredentials: credentials);

        var token = new JwtSecurityTokenHandler().WriteToken(Sectoken);
        return Ok(token);
    }
}

Secrets that are hard-coded into the application can be read by anyone with access to the source code or can be decompiled from the application binaries.

[ApiController]
[Route("login-example")]
public class LoginExampleController : ControllerBase
{
    private const string key = "SecretSecretSecretSecretSecretSecretSecretSecret";

    [HttpPost]
    public IActionResult Post([FromBody] LoginModel login)
    {
        // Code to validate the login information is omitted

        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)); // Noncompliant
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var Sectoken = new JwtSecurityToken(
            "example.com",
            "example.com",
            null,
            expires: DateTime.Now.AddMinutes(120),
            signingCredentials: credentials);

        var token = new JwtSecurityTokenHandler().WriteToken(Sectoken);
        return Ok(token);
    }
}

Compliant solution

[ApiController]
[Route("login-example")]
public class LoginExampleController : ControllerBase
{
    [HttpPost]
    public IActionResult Post([FromBody] LoginModel login)
    {
        // Code to validate the login information is omitted

        var key = Environment.GetEnvironmentVariable("JWT_KEY") ??
            throw new ApplicationException("JWT key is not configured.");
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var Sectoken = new JwtSecurityToken(
            "example.com",
            "example.com",
            null,
            expires: DateTime.Now.AddMinutes(120),
            signingCredentials: credentials);

        var token = new JwtSecurityTokenHandler().WriteToken(Sectoken);
        return Ok(token);
    }
}

How does this work?

Here, the compliant solution uses an environment variable to hold the secret. Environment variables are easy to change and are not easily accessible outside of the application.

Going the extra mile

Use a secret vault

Secret vaults provide secure methods for storing and accessing secrets. They protect against the unexpected disclosure of the secrets they store.

Microsoft recommends using Azure Key Vault with .NET Core applications.

var builder = WebApplication.CreateBuilder(args);

// Get the name of the key vault
var keyVaultName = Environment.GetEnvironmentVariable("AZURE_KEYVAULT") ??
    throw new ApplicationException("Azure Key Vault location is not configured.");
// Add Azure Key Vault in the configuration
builder.Configuration.AddAzureKeyVault(new Uri($"https://{keyVaultName}.vault.azure.net/"), new EnvironmentCredential());
// Get the JWT secret from Azure Key Vault
var jwtKey = builder.Configuration.GetSection("JWT-KEY").Get<string>() ??
    throw new ApplicationException("JWT key is not configured.");

builder.Services
  .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddJwtBearer(options => {
      options.TokenValidationParameters = new TokenValidationParameters{
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey!)),
        ValidateIssuerSigningKey = true,
        ValidIssuer = "example.com",
        ValidateIssuer = true,
        ValidAudience = "example.com",
        ValidateAudience = true,
        ValidateLifetime = true,
      };
  });

How to fix it in ASP.NET

Code examples

Noncompliant code example

Secrets stored in web.config can be read by anyone with access to the file.

public class LoginExampleController : ApiController
{
    public IHttpActionResult Post([FromBody] LoginModel login)
    {
        // Code to validate the login information is omitted

        var key = ConfigurationManager.AppSettings["key"] ??
            throw new ApplicationException("JWT key is not configured.");
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var secToken = new JwtSecurityToken(
            "example.com",
            "example.com",
            null,
            expires: DateTime.Now.AddMinutes(120),
            signingCredentials: credentials
        );

        var token = new JwtSecurityTokenHandler().WriteToken(secToken);
        return Ok(token);
    }
}

Secrets that are hard-coded into the application can be read by anyone with access to the source code or can be decompiled from the application binaries.

public class LoginExampleController : ApiController
{
    private const string key = "SecretSecretSecretSecretSecretSecretSecretSecret";

    public IHttpActionResult Post([FromBody] LoginModel login)
    {
        // Code to validate the login information is omitted

        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var secToken = new JwtSecurityToken(
            "example.com",
            "example.com",
            null,
            expires: DateTime.Now.AddMinutes(120),
            signingCredentials: credentials
        );

        var token = new JwtSecurityTokenHandler().WriteToken(secToken);
        return Ok(token);
    }
}

Compliant solution

public class LoginExampleController : ApiController
{
    public IHttpActionResult Post([FromBody] LoginModel login)
    {
        // Code to validate the login information is omitted

        var key = Environment.GetEnvironmentVariable("JWT_KEY") ??
            throw new ApplicationException("JWT key is not configured.");
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var secToken = new JwtSecurityToken(
            "example.com",
            "example.com",
            null,
            expires: DateTime.Now.AddMinutes(120),
            signingCredentials: credentials
        );

        var token = new JwtSecurityTokenHandler().WriteToken(secToken);
        return Ok(token);
    }
}

How does this work?

Here, the compliant solution uses an environment variable to hold the secret. Environment variables are easy to change and are not easily accessible outside of the application.

Resources

Documentation

Standards





© 2015 - 2024 Weber Informatics LLC | Privacy Policy