Jwt Misconfiguration on Azure
How Jwt Misconfiguration Manifests in Azure
Azure JWT misconfigurations create attack surfaces that are particularly dangerous in cloud-native environments. The most common Azure-specific manifestation occurs when developers configure Azure AD authentication but fail to properly validate token audiences, issuers, or signing keys.
In Azure Function Apps, a typical misconfiguration looks like this:
// Vulnerable: Missing audience validation
[FunctionName("GetUser")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "user/{id}")] HttpRequest req,
string id,
ILogger log)
{
var token = req.Headers["Authorization"].ToString().Replace("Bearer ", "");
var handler = new JwtSecurityTokenHandler();
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://sts.windows.net/{tenant-id}/",
ValidateAudience = false, // SECURITY RISK
ValidateLifetime = true,
ValidateIssuerSigningKey = true
};
var claimsPrincipal = handler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
return new OkObjectResult(claimsPrincipal);
} This configuration allows any token from the specified issuer to be accepted, regardless of whether it was intended for this specific API. An attacker can obtain a valid Azure AD token for a different service and use it to access this function.
Another Azure-specific pattern involves Azure API Management (APIM) policies that improperly handle JWT validation:
<!-- Vulnerable: Missing audience check in APIM policy -->
<policies>
<inbound>
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration" />
<required-claims>
<claim name="aud" match="any" separator="," />
</required-claims>
</validate-jwt>
<base />
</inbound>
</policies>The match="any" attribute allows tokens with any audience to pass validation, creating a BOLA (Broken Object Level Authorization) vulnerability where authenticated users can access resources they shouldn't have access to.
Azure App Service authentication also introduces unique misconfiguration opportunities. When using Easy Auth with JWT validation disabled:
// Vulnerable: Easy Auth with client-side JWT validation disabled
var token = req.Headers["X-MS-TOKEN-AAD-ACCESS-TOKEN"];
// No server-side validation performed
// Client-side JavaScript could validate token instead
This pattern relies on client-side validation, which is fundamentally insecure as attackers can bypass client-side checks entirely.
Azure-Specific Detection
Detecting JWT misconfigurations in Azure requires examining both configuration files and runtime behavior. Azure-specific detection focuses on the unique authentication patterns and services available in the Azure ecosystem.
For Azure Functions, middleBrick scans for these specific patterns:
{
"azure_jwt_misconfiguration": {
"function_app": {
"validate_audience_missing": true,
"audience_validation_disabled": false,
"issuer_validation_incomplete": true,
"signing_key_validation_missing": false
},
"severity": "high",
"remediation": "Add ValidateAudience = true and specify ValidAudience parameter"
}
}Azure API Management policies require XML-based detection looking for specific attribute values:
<!-- What middleBrick looks for -->
<validate-jwt ... match="any" /> <!-- HIGH RISK -->
<validate-jwt ... require-expiration-time="false" /> <!-- MEDIUM RISK -->
<validate-jwt ... require-signed-tokens="false" /> <!-- CRITICAL -->
Azure App Service authentication can be detected by examining the WEBSITE_AUTH_PRESERVE_URL_FRAGMENTS and WEBSITE_AUTH_SIGNING_KEY app settings. Missing or misconfigured signing keys indicate potential vulnerabilities.
middleBrick's Azure-specific JWT scanning includes:
- Analysis of Azure Function host.json authentication configurations
- APIM policy XML validation for JWT attributes
- App Service authentication settings inspection
- Azure AD B2C policy validation for consumer-facing applications
The scanner tests for token replay attacks by attempting to use tokens from one Azure service against another, identifying when audience validation is insufficient to prevent cross-service token reuse.
Azure-Specific Remediation
Remediating JWT misconfigurations in Azure requires using platform-native features and following Azure security best practices. Here are Azure-specific fixes for the most common vulnerabilities:
For Azure Functions, implement proper JWT validation using the Azure Functions JWT middleware:
// Secure: Complete JWT validation in Azure Functions
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Identity.Web;
using System.IdentityModel.Tokens.Jwt;
[Function("GetUserSecure")]
[Authorize]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "user/{id}")] HttpRequestData req,
string id,
FunctionContext executionContext)
{
var token = req.Headers["Authorization"].Replace("Bearer ", "");
var handler = new JwtSecurityTokenHandler();
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://sts.windows.net/{tenant-id}/",
ValidateAudience = true,
ValidAudience = "api://your-api-identifier",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuers = new[] { "https://sts.windows.net/{tenant-id}/" },
IssuerSigningKeys = GetAzureADKeys() // Dynamically fetch from Azure
};
var claimsPrincipal = handler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
// Verify audience matches expected API
var audience = validatedToken.ValidAudience;
if (audience != "api://your-api-identifier")
{
return new UnauthorizedResult();
}
return new OkObjectResult(claimsPrincipal);
}
private static IEnumerable GetAzureADKeys()
{
// Fetch Azure AD signing keys dynamically
var keys = new List();
var config = new ConfigurationManager("https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration");
var openidConfig = config.GetConfigurationAsync().Result;
keys.AddRange(openidConfig.SigningKeys);
return keys;
} For Azure API Management, use secure policy configurations:
<!-- Secure: Proper JWT validation in APIM -->
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized" require-expiration-time="true" require-signed-tokens="true" clock-skew="PT5M">
<openid-config url="https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration" />
<required-claims>
<claim name="aud" match="all" separator=",">
<value>api://your-api-identifier</value>
</claim>
<claim name="iss" match="all" separator=",">
<value>https://sts.windows.net/{tenant-id}/</value>
</claim>
</required-claims>
</validate-jwt>
For Azure App Service with Easy Auth, implement server-side validation:
// Secure: Server-side JWT validation in App Service
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
public static async Task Run(HttpRequest req, ILogger log)
{
string token = req.Headers["Authorization"].ToString().Replace("Bearer ", "");
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(
"https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration",
new OpenIdConnectConfigurationRetriever());
var config = await configManager.GetConfigurationAsync();
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = config.Issuer,
ValidateAudience = true,
ValidAudience = "api://your-api-identifier",
ValidateLifetime = true,
IssuerSigningKeys = config.SigningKeys
};
var handler = new JwtSecurityTokenHandler();
try
{
var claimsPrincipal = handler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
return new OkObjectResult(claimsPrincipal);
}
catch (SecurityTokenInvalidLifetimeException)
{
return new UnauthorizedResult();
}
catch (SecurityTokenInvalidAudienceException)
{
return new UnauthorizedResult();
}
} Azure Key Vault integration provides secure key management for JWT validation:
// Secure: Using Azure Key Vault for JWT signing keys
using Azure.Security.KeyVault.Keys;
using Azure.Identity;
public static async Task Run(HttpRequest req, ILogger log)
{
var keyVaultUri = "https://your-key-vault.vault.azure.net/";
var client = new KeyClient(new Uri(keyVaultUri), new DefaultAzureCredential());
var key = await client.GetKeyAsync("azure-ad-signing-keys");
var ecKey = key.Value.Key.ToSecurityKey();
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://sts.windows.net/{tenant-id}/",
ValidateAudience = true,
ValidateLifetime = true,
IssuerSigningKey = ecKey
};
// Continue with validation
} Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |