Что может привести к тому, что JwtSecurityTokenHandler.ValidateToken выдаст IDX10503: Ошибка проверки подписи. когда ключ действителен?

У меня есть приложение ASP.NET core 2.2, которое предоставляет конечную точку API. Эта конечная точка защищена простым токеном 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. Код проверки срока действия токена никогда не вызывается.

образцы токенов

Из приложения С# (проходит проверку):

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=

(Все эти данные взяты из локального тестового приложения, поэтому при создании этого вопроса не было секрета)


person Stephane    schedule 23.05.2019    source источник
comment
Что, если вы добавите ValidateIssuerSigningKey = false или RequireSignedTokens = false? Кроме того, в целях отладки можно установить IdentityModelEventSource.ShowPII = true;   -  person Ofiris    schedule 23.05.2019
comment
@Ofiris Ни ValidateIssuerSigningKey = false, ни RequireSignedTokens = false ничего не меняют. я обновил свой вопрос с более подробным сообщением об исключении после установки для IdentityModelEventSource.ShowPII значения true.   -  person Stephane    schedule 23.05.2019
comment
Глупый вопрос, в моих приложениях JWT мне нужно отправить ключ, подобный этому «Bearer [mykey]», вам не хватает чего-то подобного? т.е. 'Bearer' String впереди?   -  person rst    schedule 23.05.2019
comment
@ Во-первых, нет. Маркер правильно получен фреймворком и передан методу проверки. Но я обнаружил проблему: подписи токенов delphi на самом деле недействительны: меня обманул отладчик jwt.io, который повторно подпишет полезную нагрузку, если вы измените ключ.   -  person Stephane    schedule 23.05.2019


Ответы (2)


Я нашел свою проблему, и проблема в моем собственном создании.

Краткий ответ: токены Delphi недействительны, поскольку код, генерирующий подпись, содержит ошибки.

Я не заметил этого, потому что JWT.IO будет повторно генерировать подпись токена каждый раз, когда вы меняете ключ, поэтому он всегда говорил «подпись проверена», потому что моя тестовая процедура была «скопировать токен из VisualStudio, вставить его в отладчик JTW, вставить key", который на самом деле никогда не проверял исходный токен.

person Stephane    schedule 23.05.2019

Я получил именно эту ошибку и долго пытался понять, почему.

Вот мой формализованный ответ для тех, кто все еще ищет его.

При проверке в 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)}

Также всегда проверяйте, секрет один и тот же, каким бы очевидным он ни был.

person Rudy Scoggins    schedule 12.02.2021