5
votes

Comment valider JWT à l'aide de l'heure UTC à l'aide de .NET Core

Actuellement, je programme un WebApi ASP.NET-Core en utilisant l'authentification JWT-Bearer.

Pour rendre l'API accessible à partir de différents fuseaux horaires, j'utilise le modèle suivant pour définir les champs nbf (notBefore) et exp (expire) dans mon JWT vers un horodatage UTC:

var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);

...

var tokenOptions = new JwtSecurityToken(
                notBefore: utcNow,
                expires: utcNow.AddSeconds(3600),
            );
...

Pour la génération de jetons, tout fonctionne plutôt bien, nbf et exp contiennent un horodatage UNIX représentant l'heure UTC actuelle.

Mais lors de la validation des jetons, tout fonctionne pendant 5 minutes (mon réglage d'horloge) et ensuite je n'obtiens que 401 de l'API, car la validation des jetons se fait avec mon fuseau horaire actuel ici en Allemagne.

Existe-t-il un moyen de configurer JwtAuthentication-Middleware dans .NET-Core pour utiliser UTC-Time pour la validation des jetons? Ou existe-t-il d'autres moyens de résoudre ce problème?


1 commentaires

Avez-vous la solution?


3 Réponses :


1
votes

Une solution consiste à valider le jeton sans délai d'expiration. Cela renverra un jeton valide même si le jeton avait expiré. Ensuite, dans votre code, vérifiez manuellement l'heure d'expiration des jetons. Voici des extraits des codes:

public bool IsExpired(DateTime now)
{
    return JwtSecurityToken.ValidTo > now;
}

Ensuite, lorsque le jeton est validé, vérifiez l'heure d'expiration avec:

var validationParameters = new TokenValidationParameters()
{
   RequireExpirationTime = false,  // we can check manually
   ValidateIssuer = true,
   ValidateAudience = true,

   .
   .
   IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};

J'espère que cette réponse le sera aider quelqu'un.


0 commentaires

2
votes

Pour une réponse plus complète, dans votre Startup.cs:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                // ...
                ValidateLifetime = true,
                LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, 
                                     TokenValidationParameters validationParameters) => 
                {
                    return notBefore <= DateTime.UtcNow &&
                           expires >= DateTime.UtcNow;
                }
            };
        });


10 commentaires

Cela ne prend pas en compte le paramètre ClockSkew.


Pourquoi le devrait-il? Le biais d'horloge signifiera une différence maximale de quelques secondes, ce qui n'est pas pertinent pour ce type d'application ... le décalage d'horloge est un problème dont les circuits numériques doivent se soucier, pas l'authentification logicielle.


Des dérives d'horloge se produisent dans les serveurs et cela peut entraîner le rejet / l'acceptation aléatoire d'un jeton en fonction du serveur sur lequel vous vous trouvez. La raison pour laquelle cette propriété existe signifie qu'elle est importante.


De plus, la bibliothèque de ms valide déjà l'heure dans utc donc le code sur la réponse n'apporte aucune valeur ajoutée.


Je veux dire que oui, vous avez raison de dire que ClockSkew est une chose, mais par défaut, ASP.NET a défini ce paramètre à 5 minutes ... certaines circonstances très rares. ClockSkew n'est généralement désactivé que quelques secondes ... alors pourquoi jouer avec le défaut?


La valeur par défaut de 5 mn ne sera pas prise en compte avec le code que vous avez fourni car elle remplace la logique de validation à vie d'ASP.NET Core


Non, ce n'est pas précis ... sauf si cela est spécifiquement remplacé, il est défini par défaut sur 5 minutes. stackoverflow.com/a/55155711/550975


Jetez un œil au code source ou faites des tests par vous-même. Lorsque vous remplacez la validation à vie, c'est l'équivalent de dire "Je sais ce que je fais", le framework ne fait aucune validation supplémentaire concernant la durée de vie car c'est désormais la responsabilité du développeur.


Vous vous trompez ... merci de perdre mon temps à chercher le code source, mais c'est comme je l'ai dit ... à moins d'être spécifiquement remplacé, il est défini sur 5 minutes: Je ne sais pas pourquoi vous refusez de comprendre mon point. Je n'ai jamais dit que la valeur par défaut n'était pas de 5 minutes. J'ai dit ce qui suit: 1. Votre réponse n'ajoute pas de valeur anh car la validation est déjà effectuée en utc par la bibliothèque. 2. Votre réponse ne prend pas en compte la valeur définie dans ClockSkew, ce qui signifie que la validation à vie dans votre code ne se valide qu'en fonction de l'heure d'expiration sans égard à ClockSkew. J'espère que c'est clair pour vous maintenant. Consultez ma réponse, il a un lien vers le code source pertinent qui montre comment votre code empêche ClockSkew d'être pris en compte.



0
votes

C'est déjà le cas. Le package System.IdentityModel.Tokens.Jwt valide en effet la durée de vie JWT par rapport à l'heure UTC. Voici le bit correspondant de la source:

public static void ValidateLifetime(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
        {
            ...

            if (notBefore.HasValue && expires.HasValue && (notBefore.Value > expires.Value))
                throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidLifetimeException(LogHelper.FormatInvariant(LogMessages.IDX10224, notBefore.Value, expires.Value))
                { NotBefore = notBefore, Expires = expires });

            DateTime utcNow = DateTime.UtcNow;
            if (notBefore.HasValue && (notBefore.Value > DateTimeUtil.Add(utcNow, validationParameters.ClockSkew)))
                throw LogHelper.LogExceptionMessage(new SecurityTokenNotYetValidException(LogHelper.FormatInvariant(LogMessages.IDX10222, notBefore.Value, utcNow))
                    { NotBefore = notBefore.Value });
 
            if (expires.HasValue && (expires.Value < DateTimeUtil.Add(utcNow, validationParameters.ClockSkew.Negate())))
                throw LogHelper.LogExceptionMessage(new SecurityTokenExpiredException(LogHelper.FormatInvariant(LogMessages.IDX10223, expires.Value, utcNow))
                    { Expires = expires.Value });

            // if it reaches here, that means lifetime of the token is valid
            LogHelper.LogInformation(LogMessages.IDX10239);
        }

https://github.com/AzureAD/azure-activeddirectory-identity/azure-activedirectory-identity /b5b7ed8fb8ce513469b51b87c5f76314783b74e3/src/Microsoft.IdentityModel.Tokens/Validators.cs#L268


0 commentaires