HIGH unicode normalizationaspnetbasic auth

Unicode Normalization in Aspnet with Basic Auth

Unicode Normalization in Aspnet with Basic Auth — how this combination creates or exposes the vulnerability

Unicode normalization plays a subtle but important role in API security, especially when Basic Authentication is used in ASP.NET applications. Attackers can exploit normalization differences to bypass authentication or escalate privileges by providing credentials that appear equivalent but are not treated as identical by the server.

In ASP.NET, Basic Authentication typically involves extracting credentials from the Authorization header, decoding the base64-encoded username:password pair, and validating them against a user store. If the application normalizes the username or password inconsistently—or fails to normalize at all—credentials like café (U+00E9) and café (U+0065 + combining acute accent) may be treated as different values. An attacker can send the non-normalized form while the server stores or compares the normalized form, leading to authentication bypass or account confusion.

When using ASP.NET Core Identity or custom user stores, developers must ensure normalization is applied consistently during both user registration and login. For example, if passwords are normalized before hashing during registration but not normalized before comparison during login, an attacker could supply a visually identical but differently encoded password that fails to match. Similarly, usernames used in route parameters or claims must be normalized to prevent IDOR or BOLA issues where /users/café/settings and /users/café/settings resolve to different resources.

Basic Authentication over unencrypted channels compounds the risk. Although middleBrick checks for encryption and flags missing transport-layer protections, developers must also ensure that credentials are normalized before any comparison or hashing. Without normalization, attackers can craft requests that exploit encoding variations to gain unauthorized access, even when the transport is secured.

Basic Auth-Specific Remediation in Aspnet — concrete code fixes

To mitigate Unicode normalization issues with Basic Authentication in ASP.NET, normalize both usernames and passwords consistently using the same Unicode form (typically NFC) before storage and comparison.

Below is a concrete example implementing Basic Authentication with normalization in ASP.NET Core. It uses System.Text.Normalization to ensure consistent encoding and demonstrates secure handling of credentials.

using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Normalization;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

public class BasicAuthenticationOptions : AuthenticationSchemeOptions
{
    public string Realm { get; set; } = "Protected API";
}

public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
    private readonly IUserStore _userStore;

    public BasicAuthenticationHandler(
        IOptionsMonitor<BasicAuthenticationOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock,
        IUserStore userStore)
        : base(options, logger, encoder, clock)
    {
        _userStore = userStore;
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.ContainsKey("Authorization"))
            return AuthenticateResult.Fail("Missing Authorization Header");

        var authHeader = Request.Headers["Authorization"].ToString();
        if (!authHeader.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
            return AuthenticateResult.Fail("Invalid Authorization Scheme");

        var token = authHeader.Substring("Basic ".Length).Trim();
        var credentialBytes = Convert.FromBase64String(token);
        var credentials = Encoding.UTF8.GetString(credentialBytes);
        var parts = credentials.Split(':', 2);
        if (parts.Length != 2)
            return AuthenticateResult.Fail("Invalid Credentials Format");

        var usernameRaw = parts[0];
        var passwordRaw = parts[1];

        // Normalize using NFC to ensure consistent representation
        var username = usernameRaw.Normalize(NormalizationForm.FormC);
        var password = passwordRaw.Normalize(NormalizationForm.FormC);

        var user = await _userStore.FindByNameAsync(username);
        if (user == null || !VerifyPassword(user, password))
            return AuthenticateResult.Fail("Invalid Username or Password");

        var claims = new[] { new Claim(ClaimTypes.Name, user.Username) };
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, Scheme.Name);

        return AuthenticateResult.Success(ticket);
    }

    private bool VerifyPassword(User user, string providedPassword)
    {
        // Use a secure hashing mechanism such as PBKDF2, bcrypt, or Argon2
        // This example assumes user.PasswordHash is stored as a normalized hash
        var hashToCompare = HashPassword(providedPassword);
        return CryptographicOperations.FixedTimeEquals(
            Encoding.UTF8.GetBytes(hashToCompare),
            Encoding.UTF8.GetBytes(user.PasswordHash));
    }

    private string HashPassword(string password)
    {
        // Placeholder: implement with a strong KDF in production
        using var sha256 = SHA256.Create();
        var bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
        return Convert.ToBase64String(bytes);
    }
}

Key remediation steps include normalizing input with string.Normalize(NormalizationForm.FormC) before comparison and hashing, ensuring that user stores and authentication logic use the same Unicode form. This prevents bypass via homoglyphs or combining characters and aligns with secure handling practices for identifiers in ASP.NET applications.

Frequently Asked Questions

Can Unicode normalization issues also affect token-based authentication in ASP.NET?
Yes. If tokens, claims, or usernames are compared without normalization, equivalent but differently encoded values can lead to bypass or misidentification. Normalize tokens and usernames consistently.
Does middleBrick detect missing Unicode normalization in API authentication flows?
middleBrick tests authentication and input validation checks that can surface inconsistent handling of identifiers. Review findings for guidance on normalizing usernames and passwords to NFC.