无法验证 AAD 访问令牌 - IDX10511:签名验证失败

问题描述 投票:0回答:3

我正在尝试构建一种验证我的令牌的方法。我正在使用 Open Id Connect 授权代码流从 Azure Active Directory 检索我的令牌。我获得的令牌是 access_tokenid_token。我正在使用 .NET Core。

我的验证码如下:

string stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
var handler = new JwtSecurityTokenHandler();
ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;

try
{
  TokenValidationParameters validationParameters = new TokenValidationParameters
  {
     ValidIssuers = new [] { "https://login.microsoftonline.com/tenantid/v2.0" },
     ValidAudiences = new [] { "client-Id" },
     ValidateAudience = true,
     ValidateIssuer = true,
     IssuerSigningKeys = config.SigningKeys,
     ValidateLifetime = true
  };
  var tokenHandler = new JwtSecurityTokenHandler();
  SecurityToken validatedToken = null;
  tokenHandler.ValidateToken(token.AccessToken, validationParameters, out validatedToken);
  return validatedToken != null;
 }
 catch (SecurityTokenInvalidSignatureException ex)
 {
   return false;
 }
 catch(SecurityTokenValidationException)
 {
   return false;
 }

下面的代码适用于id_token但是 对于 access_token 不起作用

对 access_token 执行此方法时收到的错误消息是:

IDX10511:签名验证失败。尝试过的密钥: 'Microsoft.IdentityModel.Tokens.X509SecurityKey ,KeyId:CtAAALb-8NsDe333734859crfOc '。 孩子:“CtAAALb-8NsDe333734859crfOc”。 捕获的异常: ' '

azure azure-active-directory access-token
3个回答
7
投票
在签名验证之前,随机数标头必须经过 SHA2 哈希处理

这是一个代码示例,您可以在其中看到

jsonToken.Header.Add("nonce", hashedNonce);
        private static bool _hashNonceBeforeValidateToken = true;
        private const string MicrosoftGraphApplicationId = "00000003-0000-0000-c000-000000000000";
        private const string MicrosoftIssuer = "https://sts.windows.net";


    public static bool ValidateTokenSignature(string accessToken, ApplicationConfiguration applicationConfiguration) {
        var tokenHandler = new JwtSecurityTokenHandler();
        var jsonToken = tokenHandler.ReadJwtToken(accessToken);
        string[] parts = accessToken.Split('.');
        string header = parts[0];
        string payload = parts[1];
        string signature = parts[2];

        //hash nonce and update header with the hash before validating
        if (_hashNonceBeforeValidateToken &&
            jsonToken.Header.TryGetValue("nonce", out object nonceAsObject))
        {
            string plainNonce = nonceAsObject.ToString();
            using (SHA256 sha256 = SHA256.Create())
            {
                byte[] hashedNonceAsBytes = sha256.ComputeHash(
                    System.Text.Encoding.UTF8.GetBytes(plainNonce));
                string hashedNonce = Base64Url.Encode(hashedNonceAsBytes);
                jsonToken.Header.Remove("nonce");
                jsonToken.Header.Add("nonce", hashedNonce);
                header = tokenHandler.WriteToken(jsonToken).Split('.')[0];

                accessToken = $"{header}.{payload}.{signature}";
            }
        }

        //get the Microsoft JWT signature public key 
        string stsDiscoveryEndpoint = $"https://login.microsoftonline.com/{applicationConfiguration.TenantId}/v2.0/.well-known/openid-configuration";
        if (jsonToken.Header.TryGetValue("ver", out object version) && version.ToString() == "1.0")
        {
            stsDiscoveryEndpoint = $"https://login.microsoftonline.com/{applicationConfiguration.TenantId}/.well-known/openid-configuration";
        }
        var openidConfigManaged = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint,
            new OpenIdConnectConfigurationRetriever(),
            new HttpDocumentRetriever());
        var configTask = openidConfigManaged.GetConfigurationAsync();
        configTask.Wait();
        var config = configTask.Result;

        var parameteres = new TokenValidationParameters()
        {
            RequireAudience = true,
            ValidateAudience = true,
            ValidAudiences = new[] { applicationConfiguration.ApplicationId, MicrosoftGraphApplicationId },

            ValidateIssuer = true,
            ValidIssuers = new string[] { $"{MicrosoftIssuer}/{applicationConfiguration.TenantId}/", config.Issuer },

            IssuerSigningKeys = config.SigningKeys,
            ValidateIssuerSigningKey = true,

            RequireExpirationTime = true,
            ValidateLifetime = true,
        };

        var claimPrincipal = tokenHandler.ValidateToken(
            accessToken, parameteres, out SecurityToken validatedToken);

        return claimPrincipal.Identity.IsAuthenticated;
    }

    

1
投票

access_token

受众是您的 API 或 Microsoft Graph/其他第 3 方服务吗?只有验证“你”(你的服务)消耗的代币才有意义,其他受众将自行处理此问题。最重要的是,该 JWT 的签名对您来说可能是不透明的。
请参阅此了解更多信息 - https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/812#issuecomment-456700813

当您不创建自定义范围时,就会发生这种情况。在这种情况下,MSAL 生成标头中具有“nonce”的 JWT。此类 JWT 无法通过您的 .net 代码轻松验证。但是,如果您确实创建了自定义范围(如此处

0
投票
)并在请求时指定它访问令牌,那么 MSAL 不会将

nonce 添加到标头中,这样的 JWT 可以在没有额外痛苦的情况下进行验证。

© www.soinside.com 2019 - 2024. All rights reserved.