c# - JwtSecurityToken no caduca cuando debería

CorePress2024-01-24  11

Actualmente estoy usando la clase JwtSecurityToken en el espacio de nombres System.IdentityModels.Tokens. Creo un token usando lo siguiente:

DateTime expires = DateTime.UtcNow.AddSeconds(10);
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var genericIdentity = new System.Security.Principal.GenericIdentity(username, "TokenAuth");

ClaimsIdentity identity = new ClaimsIdentity(claims);
string secret = ConfigurationManager.AppSettings["jwtSecret"].ToString();
var securityKey = new     InMemorySymmetricSecurityKey(Encoding.Default.GetBytes(secret));
var signingCreds = new SigningCredentials(securityKey,     SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.HmacSha256Signature);
var securityToken = handler.CreateToken(
    issuer: issuer,
    audience: ConfigurationManager.AppSettings["UiUrl"].ToString(),
    signingCredentials: signingCreds,
    subject: identity,
    expires: expires,
    notBefore: DateTime.UtcNow
);
return handler.WriteToken(securityToken); 

Por alguna razón, aunque la caducidad está configurada en 10 segundos después de la hora actual, en realidad no genera una excepción cuando el token se valida hasta aproximadamente 5 minutos. Después de ver esto, pensé que tal vez había un tiempo mínimo de caducidad de 5 minutos, así que configuré el tiempo de caducidad en:

DateTime.UtcNow.AddMinutes(5);

Luego caduca a los 10 minutos, pero el mensaje de excepción dice que el tiempo de caducidad está establecido en lo que se supone que es (5 minutos después de que el usuario inicia sesión), y cuando muestra la hora actual en la excepción es 5 minutos después del tiempo de caducidad. Entonces, parece saber cuándo DEBE caducar, pero en realidad no arroja elexcepción hasta 5 minutos después del tiempo de caducidad. Luego, dado que el token parece estar agregando 5 minutos al tiempo que configuré para que caduque, configuré el tiempo de caducidad en:

DateTime.UtcNow.AddMinutes(-5).AddSecond(10);

Probé esto y hasta ahora todavía no ha caducado (después de más de diez minutos). ¿Alguien puede explicar por qué sucede esto y qué estoy haciendo mal? Además, si ve algo más con el código que proporcioné, agradecería cualquier orientación ya que soy nuevo en el uso de JWT y esta biblioteca.



------------------------------------

El problema está relacionado con ClockSkew. Normalmente, las bibliotecas de validación (al menos la de MS) compensan la desviación del reloj. Valor predeterminado de ClockSkewEl valor es de 5 minutos. Vea alguna respuesta aquí

Puedes cambiar ClockSkew en TokenValidationParameters:

var tokenValidationParameters = new TokenValidationParameters
{
    //...your setting

    // set ClockSkew is zero
    ClockSkew = TimeSpan.Zero
};

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = tokenValidationParameters
});
Respondido al

15 de septiembre de 2017 a las 3:11

Hien

Hien

2.060

2

2 insignias de oro

18

18 insignias de plata

14

14 insignias de bronce

0



------------------------------------

Después de leer la respuesta de @Denis Kucherov, descubrí que podía usar el mismo validador personalizado que élpublicado sin usar la clase JwtBearerOptions, lo que me habría requerido agregar una nueva biblioteca.

Además, dado que hay dos espacios de nombres que contienen muchas de estas mismas clases, me aseguraré de mencionar que todos ellos utilizan los espacios de nombres System.IdentityModels.... (NO Microsoft.IdentityModels...)

A continuación se muestra el código que terminé usando:

private bool CustomLifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken tokenToValidate, TokenValidationParameters @param)
{
    if (expires != null)
    {
        return expires > DateTime.UtcNow;
    }
    return false;
}
private JwtSecurityToken ValidateJwtToken(string tokenString)
{
   string secret = ConfigurationManager.AppSettings["jwtSecret"].ToString();
   var securityKey = new InMemorySymmetricSecurityKey(Encoding.Default.GetBytes(secret));
   JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
   TokenValidationParameters validation = new TokenValidationParameters()
   {
       ValidAudience = "MyAudience",
       ValidIssuer = "MyIssuer",
       ValidateIssuer = true,
       ValidateLifetime = true,
       LifetimeValidator = CustomLifetimeValidator,
       RequireExpirationTime = true,
       IssuerSigningKey = securityKey,
       ValidateIssuerSigningKey = true,
   };
   SecurityToken token;
   ClaimsPrincipal principal = handler.ValidateToken(tokenString, validation, out token);
   return (JwtSecurityToken)token;
}



------------------------------------

Parece haber algún problema con LifeTimeValidator. Puedes simplemente anular su lógica con un delegado personalizado. Además, utilice la clase JwtBearerOptions para controlar el comportamiento del middleware de autenticación. Por ejemplo:

new JwtBearerOptions
{
     AutomaticAuthenticate = true,
     AutomaticChallenge = true,
     TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
     {
           ValidIssuer = _configuration["Tokens:Issuer"],
           ValidAudience = _configuration["Tokens:Audience"],
           ValidateIssuer = true,
           ValidateAudience = true,
           ValidateLifetime = true,
           LifetimeValidator = LifetimeValidator,
           ValidateIssuerSigningKey = true,
           IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Tokens:Key"]))
      }
}

Y asigne un delegado LifetimeValidotor para proporcionar su propia lógica de validación de tiempo de espera:

private bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken token, TokenValidationParameters @params)
{
     if (expires != null)
     {
          return expires > DateTime.UtcNow;
     }
     return false;
}
Respondido

14/08/2017 a las 14:00

Denis Kucherov

Denis Kucherov

379

3

3 insignias de plata

15

15 insignias de bronce

5

JwtBearerOptions parece requerir otra biblioteca. Lo comprobé aquí:nuget.org/packages/Microsoft.AspNet.Authentication.JwtBearer e intenté instalar nuget. Falla cada vez, a pesar de que mi proyecto está en .net 4.5.1. "No se pudo instalar el paquete 'Microsoft.AspNet.Authentication.JwtBearer 1.0.0-beta8'. Está intentando instalar este paquete en un proyecto destinado a '.NETFramework,Version=v4.5.1', pero el paquete no contiene ninguna referencia de ensamblado ni archivos de contenido que sean compatibles con ese marco". ¿Alguna idea de por qué no me deja instalar?

-tkd_aj

18/08/2017 a las 20:40

@tkd_aj- Pruebe este: nuget.org/packages/…

- Denis Kucherov

19/08/2017 a las 6:28

Ese es para ASP.NET Core. Nuestro proyecto utiliza ASP.NET 4.5.1. Supongo que eso no va a funcionar.

-tkd_aj

21/08/2017 a las 20:04

@tkd_aj Pruebe la versión 1.1.2, debería funcionar en 4.5.1 y .NET Standart 1.4

- Denis Kucherov

22/08/2017 a las 8:46

Esa versión de la biblioteca se instaló correctamente. Sin embargo, después de instalarlo, no pude encontrar una manera de USAR realmente el objeto JwtBearerOptions que había creado. Miré por todas partes y solo encontré que se usaba en ASP.NET core como middleware usando el método app.use(). PERO, mientras exploraba, descubrí que podía asignar el mismo validador personalizado que publicaste anteriormente en mi código existente donde estaba validando elsimbólico. Votaré tu respuesta y publicaré el código que terminé usando al final. ¡Gracias por ayudarme a resolver este problema!

-tkd_aj

25/08/2017 a las 17:22



------------------------------------

Actualización de .NET Core

Esto se maneja de manera ligeramente diferente en .NET Core, ya que los TokenValidationParameters se configuran en Startup.cs usando el método ConfigureServices() y luego el middleware los maneja automáticamente.

Tenga en cuenta también que la antigua InMemorySymmetricSecurityKey para firmar el secreto ahora está obsoleta en favor de SymmetricSecurityKey, que se muestra a continuación.

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = _config.AuthenticationSettings.TokenAuthority,
                ValidAudience = _config.AuthenticationSettings.TokenAuthority,
                LifetimeValidator = TokenLifetimeValidator.Validate,
                IssuerSigningKey = new SymmetricSecurityKey(
                    Encoding.UTF8.GetBytes(_config.AuthenticationSettings.SecurityKey))
            };
        });

    // ...
}

Y entonces también hice mi propia versión del validador de tokens en @tla respuesta de kd_aj anterior y la arrojó en una clase estática:

public static class TokenLifetimeValidator
{
    public static bool Validate(
        DateTime? notBefore,
        DateTime? expires,
        SecurityToken tokenToValidate,
        TokenValidationParameters @param
    ) {
        return (expires != null && expires > DateTime.UtcNow);
    }
}

1

Esto casi funciona. Sin embargo, llamar a tokenHandler.ValidateToken(...) ahora generará una SecurityTokenInvalidLifetimeException cuando el método Validate devuelva false.

- Jens

18/03/2021 a las 22:16



------------------------------------

Acabo de implementar también un middleware de token JWT y, aunque los ejemplos en Internet usan UtcNow, tuve que usar Now o el tiempo de caducidad se acabó. Cuando uso Now, la caducidad es perfecta.

3

¿Estás utilizando la versión 5.0 de la biblioteca Jwt? ¿O estás usando el núcleo Asp.Net? Comencé a usar DateTime. Ahora tuve el mismo problema. Desafortunadamente, estoy usando la biblioteca 4.0 porque no podemos usar .NET 4.5. La versión 5.0 de la biblioteca Jwt requiere .NET 4.6, por lo que no podemos usarla.

-tkd_aj

27/09/2016 a las 23:27

@tkd_aj - ah... estoy usando Core. Tuve el problema del tiempo libre al usar UtcNow, YMMV :).

- Mazo

27/09/2016 a las 23:38

Ah, sí. Vi que AspNet core en realidad tenía un paquete nuget que podías descargar y haría el middleware por ti... Desafortunadamente, eso no está disponible para .NET 4.5. Gracias¡Pero por tu comentario!

-tkd_aj

28/09/2016 a las 1:50



------------------------------------

El siguiente enlace le brinda la respuesta exacta, ya que de forma predeterminada, MS tiene un tiempo de caducidad de 5 minutos. Entonces, o tienes que hacerlo a medida o con tiempo que cederás. caduca: DateTime.Now.AddSeconds(30) Se agregarán 30 segundos en la línea anterior al tiempo de vencimiento. Por lo tanto, el tiempo total de caducidad será de 5 minutos y 30 segundos

https://github.com/IdentityServer/IdentityServer3/issues/1251

Espero que esto ayude.

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare