5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ASP.NET CoreでJWTがExpireしないのはClockSkewのクセがすごいから?

Last updated at Posted at 2021-02-12

JWTがExpireしない

ASP.NET CoreでAPIを作るときにJWT認証を実装したところ、発行したJWTのExpire、すなわちトークンの期限、すなわちと言い直すなら最初からトークンの期限と書けと思いますが、とにかく、JWTのExpirationが思ったとおりに行かなかったのでレポートします。

実装例:クライアントにトークンを発行してあげる側

トークンの発行
var tokenHandler = new JwtSecurityTokenHandler();

var tokenDescriptor = new SecurityTokenDescriptor
{
    Issuer = _config["Jwt:Issuer"],
    Audience = _config["Jwt:Audience"],
    Expires = DateTime.UtcNow.AddMinutes(double.Parse(_config["Jwt:ExpireMinutes"])), // たとえば1分を設定
    Subject = new ClaimsIdentity(new[]
    {
        new Claim(ClaimTypes.NameIdentifier, useridとか),
    }),
    SigningCredentials = new SigningCredentials(
        new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_config["Jwt:Secret"])),
        SecurityAlgorithms.HmacSha256Signature)
};

var token = tokenHandler.CreateToken(tokenDescriptor);

return tokenHandler.WriteToken(token);

例:リクエストにくっついてきたトークンを検証する側

トークンを検証
services.AddAuthentication(
        JwtBearerDefaults.AuthenticationScheme
        )
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = config["Jwt:Issuer"],
            ValidAudience = config["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Secret"])),

            ClockSkew = TimeSpan.Zero // ←これがポイント
        };
    });

細かい実装アプローチに差はあれど、おおまかにはオーソドックスなASP.NET CoreのJWTサポートを利用したコードかと思います。(この記事を記載してた時点で3.1を利用してます。)

さて、試してみよう

クライアントがトークンを得ずAPIを実行する
401
クライアントがトークンを得てそのトークンをAuthorization Bearer ey~~ とHttpヘッダにつける
トークン発行10秒後にAPIを実行する
200
トークン作戦成功!嬉しくなってトークン発行20秒後にもっかいAPIを実行する
200
いいぞ!勝利の余韻に浸ったため3回目はトークン発行70秒後にAPIを実行する
200 ← は?
そしてしばらく待ち、もう1回、、
401

う~ん。。

問題発生。発行されたJWTは1分後には期限切れにしてほしいから SecurityTokenDescriptor.Expire で 1分 としたのに、これ動いてないじゃないか?いろいろ書き方を変えても結果は変わらず。
しばらく調査していると、トークン検証ロジックのほうで

options.TokenValidationParameters = new TokenValidationParameters
・・・
ClockSkew = TimeSpan.Zero // ←これがポイント

このClockSkewプロパティ、JWTのLifeTime検証の際の時間のずれを設定するという謎のプロパティで、デフォルトは 5分 らしい。
な、、なんだってー!!
たぶん Expireを設定しない場合のJWTは5分で期限切れ になるということなんでしょうね。

これを適切に設定することで、狙いどおりに期限切れを起こすことができます。
クセがすごい!

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?