2

我有一个公开 API 端点的 ASP.NET 核心 2.2 应用程序。该端点受一个简单的 JWT 令牌保护,该令牌只关心主题、过期和签名(使用共享密钥的 SHA256)。

当我从 .net 核心客户端调用端点时,它工作正常。

我现在正试图从 Delphi 客户端调用相同的代码,但服务器拒绝这些令牌,我不知道为什么:两个令牌看起来与我相同,它们都通过了 jwt.io 的验证测试

服务器端令牌验证码:

    private static TokenValidationParameters GetValidationParameters(byte[] key)
    {
        return new TokenValidationParameters()
        {
            ValidateLifetime = true,
            LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) =>
            {
                // Cutom validity validation
                DateTime current = DateTime.UtcNow; // get a single value for "now"
                // check if the token expiration is valid and if it doesn't expire 
                bool value = (expires.HasValue) && (notBefore.HasValue) && // both "expires" and "notBefore" must be set
                              (expires >= current) && // "expires" must not be in the past
                              (expires <= current.AddMinutes(5)) && // "expires" must not be any further than 5 minutes in the future
                              (notBefore <= current); // notBefore must be in the past or present
                return value;
            },
            RequireExpirationTime = true, 
            // the token has no audience or issuer so ignore these
            ValidateAudience = false, 
            ValidateIssuer = false,   
            IssuerSigningKey = new SymmetricSecurityKey(key)
        };
    }

    private bool ValidateToken(string authToken, byte[] key)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var validationParameters = GetValidationParameters(key);

        // This will raise an exception if the security token is invalid
        try
        {
            tokenHandler.ValidateToken(authToken, validationParameters, out SecurityToken validatedToken);
        }
        catch (SecurityTokenException e) // this will happen if the token is properly formated but invalid (signature, validity)
        {
            logger.LogInformation("Invalid token received: {1}", e.Message);
            return false;
        }
        return true;
    }

错误发生在tokenHandler.ValidateToken通话中。令牌过期验证码永远不会被调用。

样本令牌

从 C# 应用程序(通过验证):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NjM2MDQ1My1CMDJCLUU5MTEtODM5Qy1BMEE4Q0QzQUNCRjgiLCJuYmYiOjE1NTg2MTMzOTQsImV4cCI6MTU1ODYxMzY5NCwiaWF0IjoxNTU4NjEzMzk0fQ.nso4xnllNc-rXfn5riOWv5fZjNeJMgoQbyXeOltDYb0

从我的 Delphi 应用程序(失败):

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2NjM2MDQ1My1CMDJCLUU5MTEtODM5Qy1BMEE4Q0QzQUNCRjgiLCJpYXQiOjE1NTg2MTYxNTgsIm5iZiI6MTU1ODYxNjE1OCwiZXhwIjoxNTU4NjE2NDU4fQ.vB_gotDk1JGiiDWPT0t6TR471Av4r-LXSgc3zab7EaU

报告的错误:

IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey , KeyId: 
'.
Exceptions caught:
 ''.
token: '{"typ":"JWT","alg":"HS256"}.{"sub":"66360453-B02B-E911-839C-A0A8CD3ACBF8","iat":1558616158,"nbf":1558616158,"exp":1558616458}'.

两个令牌都使用相同的共享密钥(b64 编码)进行保护:

NdFCOQReqUk0mxTqI7psd9JrVjgE7bdPVfjILEa4dzE=

(所有这些数据都来自本地测试应用程序,因此产生这个问题没有任何秘密)

4

2 回答 2

0

我发现了我的问题,问题是我自己造成的。

简短回答:Delphi 令牌无效,因为生成签名的代码被窃听。

我没有注意到这一点,因为每次更改密钥时 JWT.IO 都会重新生成令牌签名,所以它总是说“签名已验证”,因为我的测试例程是“从 VisualStudio 复制令牌,将其粘贴到 JTW 调试器中,粘贴密钥”,嗯,它从未真正验证过原始令牌。

于 2019-05-23T15:29:53.013 回答
0

我得到了这个确切的错误,并花了很长时间试图找出原因。

对于仍在寻找它的任何人,这是我的正式答案。

在 C# 或 VB 中进行验证时,您必须考虑各种编码。

Dim symmetricKey = (New Guid(secret)).ToByteArray() 'This array encoding is used by .NET

Dim symmetricKeyUTF8 = (Text.Encoding.UTF8.GetBytes(secret)) 'This is used by Javascript and our Postman example

Dim issuerSigningKeys = New List(Of SecurityKey) From {New SymmetricSecurityKey(symmetricKey), New SymmetricSecurityKey(symmetricKeyUTF8)}

还要始终检查秘密是否相同,无论它多么明显。

于 2021-02-12T19:56:13.523 回答