logo

Business information leak - Analytics - Csharp


Need

Protection of sensitive business information from unauthorized access


Context

  1. Usage of C# 7.0 for modern language features and enhancements
  2. Usage of Microsoft.AspNetCore.Authentication for implementing authentication in ASP.NET Core applications
  3. Usage of Microsoft.AspNetCore.Authentication.JwtBearer for JWT-based authentication in ASP.NET Core
  4. Usage of Microsoft.AspNetCore.Hosting for hosting ASP.NET Core applications
  5. Usage of Microsoft.AspNetCore.Http for handling HTTP requests and responses in ASP.NET Core applications
  6. Usage of Microsoft.AspNetCore.Mvc for building web applications with ASP.NET Core
  7. Usage of Microsoft.AspNetCore.Mvc.Versioning for API versioning in ASP.NET Core MVC
  8. Usage of Microsoft.Extensions.Configuration for managing application configuration
  9. Usage of Microsoft.Extensions.DependencyInjection for managing dependency injection in a .NET application
  10. Usage of Microsoft.Extensions.Hosting for building and hosting .NET Core applications
  11. Usage of Microsoft.Extensions.Options for managing and accessing configuration options in a .NET application
  12. Usage of Microsoft.OpenApi.Models for working with OpenAPI specifications in .NET applications
  13. Usage of Newtonsoft.Json for JSON serialization and deserialization

Description

Insecure Code Example

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
        });

        services.AddSwaggerGenNewtonsoftSupport();

        // Configuration for API Key
        services.AddAuthentication()
            .AddScheme<AuthenticationSchemeOptions, ApiKeyAuthenticationHandler>("ApiKey", options => { });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        });

        app.UseAuthentication();
    }
}

public class ApiKeyAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.TryGetValue("ApiKey", out var apiKeyHeaderValues))
            return Task.FromResult(AuthenticateResult.Fail("ApiKey was not provided."));
       
        var providedApiKey = apiKeyHeaderValues.FirstOrDefault();

        if (providedApiKey == null)
            return Task.FromResult(AuthenticateResult.Fail("ApiKey was not provided."));

        if (providedApiKey != "Your_Secret_ApiKey")
            return Task.FromResult(AuthenticateResult.Fail("Invalid ApiKey provided."));

        var claims = new List<Claim> { new Claim(ClaimTypes.Name, "ApiKeyUser") };
        var identity = new ClaimsIdentity(claims, "ApiKey");
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, "ApiKey");

        return Task.FromResult(AuthenticateResult.Success(ticket));
    }
}

The code above represents an ASP.NET Core application that uses Swagger for API documentation. The API Key is being used for authentication. The vulnerability lies in the way the API key is being handled. The API Key is hardcoded in the `HandleAuthenticateAsync` method of the `ApiKeyAuthenticationHandler` class. This is a bad practice because anyone who has access to the codebase can see the API Key. Furthermore, the Swagger UI is publicly accessible as the `UseSwaggerUI` middleware is used without any restriction. This allows anyone with the hardcoded API Key to access the Swagger UI and potentially gain insights from the analytics data exposed by the API. This can lead to a business information leak, as sensitive data might be exposed.

Steps

  1. Remove the Swagger URL that exposes the business insights from mobile app usage analytics.
  2. Do not include the APIKey in the Swagger documentation or any other publicly accessible documentation.
  3. Implement proper access control mechanisms to restrict access to the business insights.
  4. Consider using a secure and encrypted channel (e.g., HTTPS) for transmitting the APIKey.
  5. Ensure that the APIKey is securely stored and not hardcoded in the code.
  6. Regularly rotate the APIKey to minimize the risk of unauthorized access.
  7. Implement rate limiting and throttling mechanisms to prevent abuse and excessive usage of the API.
  8. Monitor and log API usage to detect any suspicious or unauthorized access attempts.

Secure Code Example

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication()
            .AddScheme<AuthenticationSchemeOptions, ApiKeyAuthenticationHandler>("ApiKey", options => { });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseAuthentication();
    }
}

public class ApiKeyAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly IConfiguration _configuration;

    public ApiKeyAuthenticationHandler(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.TryGetValue("ApiKey", out var apiKeyHeaderValues))
            return Task.FromResult(AuthenticateResult.Fail("ApiKey was not provided."));
       
        var providedApiKey = apiKeyHeaderValues.FirstOrDefault();

        if (providedApiKey == null)
            return Task.FromResult(AuthenticateResult.Fail("ApiKey was not provided."));

        var storedApiKey = _configuration["StoredApiKey"];

        if (providedApiKey != storedApiKey)
            return Task.FromResult(AuthenticateResult.Fail("Invalid ApiKey provided."));

        var claims = new List<Claim> { new Claim(ClaimTypes.Name, "ApiKeyUser") };
        var identity = new ClaimsIdentity(claims, "ApiKey");
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, "ApiKey");

        return Task.FromResult(AuthenticateResult.Success(ticket));
    }
}

The updated code removes the Swagger documentation that was previously exposing the APIKey and business insights. The APIKey is no longer hardcoded in the code, instead it is retrieved from a secure configuration source (e.g., environment variables, secure configuration files, or a secure key vault). The `ApiKeyAuthenticationHandler` now includes a constructor that takes an `IConfiguration` object, which is used to retrieve the stored APIKey. This ensures that the APIKey is securely stored and not exposed in the code. The `HandleAuthenticateAsync` method checks if the provided APIKey matches the stored APIKey. If the APIKeys do not match, it returns an authentication failure. This code should be used in conjunction with other security measures such as using a secure and encrypted channel (e.g., HTTPS) for transmitting the APIKey, implementing proper access control mechanisms, regularly rotating the APIKey, implementing rate limiting and throttling mechanisms, and monitoring and logging API usage.


References

  • 228 - Business information leak - Analytics

  • Last updated

    2023/09/18