JWT验证失败

avs*_*sln 4 c# jwt

我通过设置Payload创建了一个JwtToken,如下所示

var payload = new JwtPayload
        {
            {"aud", "wellmark.com" },
            {"iss", "wellmark" },
            {"iat", DateTime.Now.Ticks },
            {"exp", DateTime.Now.AddDays(90).Ticks },
        };
Run Code Online (Sandbox Code Playgroud)

我必须使用ticks的原因是因为这是获得发布时间和到期时间的整数值的唯一方法.我同意ticks实际上是一个很长的而不是int,但这是唯一的方法.

现在,当我回来验证令牌时,我正在执行以下操作

var tokenValidationParams = new TokenValidationParameters
            {
                IssuerSigningKey = new X509SecurityKey(jwtCert),
                ValidAudience = "masked",
                ValidIssuer = "masked",
                IssuerSigningKeyResolver = (string token, Microsoft.IdentityModel.Tokens.SecurityToken securityToken, string kid, TokenValidationParameters validationParameters) => new List<X509SecurityKey> { new X509SecurityKey(jwtCert) }
            };

            tokenHandler.ValidateToken(id, tokenValidationParams
                   , out validatedToken);
Run Code Online (Sandbox Code Playgroud)

然而,这是失败的说法

终身验证失败.令牌缺少过期时间.Tokentype:'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'.

这很可能是因为验证方法试图长转换成int型,因为它无法将其转换,它只是返回一个空如图所示的文件中表示 这里.

有没有人在这个机制上取得成功.请注意,我使用X509证书签署我的Jwt.

拉辛哈

jps*_*jps 7

您不能将Ticks用于exp时间戳

JWT中的时间戳是UNIX时间戳,从01.01.1970 00:00 UTC开始计算:https://tools.ietf.org/html/rfc7519#section-4.1.4解释了数字日期用于exp声明(以及对于nbf(不是之前)和iat(发布于)索赔)

https://tools.ietf.org/html/rfc7519#section-2定义数字日期:

一个JSON数值,表示从1970-01-01T00:00:00Z UTC到指定的UTC日期/时间的秒数,忽略闰秒.

如果您像在示例中那样直接创建有效负载,则需要计算自1.1.1970 UTC以来的秒数,例如:

DateTime centuryBegin = new DateTime(1970, 1, 1);
var exp = new TimeSpan(DateTime.Now.AddDays(90).Ticks - centuryBegin.Ticks).TotalSeconds;
Run Code Online (Sandbox Code Playgroud)

exp是90天后的.当然,您也可以使用任何其他Add ...方法来计算实验时间.请参阅https://msdn.microsoft.com/de-de/library/system.datetimeoffset(v=vs.110).aspx以查看其他添加方法.

一些框架(例如System.IdentityModel.Tokens.Jwt)提供了创建令牌的函数,这些令牌接受DateTimeOffset类型的参数,这些参数更容易处理.

使用http://www.unixtimestamp.com/或类似网站检查您的时间戳


Awa*_*Teh 7

另外一点值得注意的是,虽然@jps答案居然是技术上是正确的,它真的不解释为什么你得到了异常:Lifetime validation failed. The token is missing an Expiration Time. Tokentype: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'; 为什么它会暗示你错过了一个到期时间,即使你已经明确地提供了一个Int64(长)?从理论上讲,即使考虑到从January 1st 1970(https://tools.ietf.org/html/rfc7519#section-2)开始的epcoh时间限制,任何Int64号码都应代表未来的某个时间点.

真正的潜在问题是,当您使用Ticks时使用的数字是一个非常大的数字; 首先,微软将其定义为:

自公元0001年1月1日午夜12:00:00(格林历日历0001年1月1日0:00:00起)以来经过的100纳秒间隔的数量.https://msdn.microsoft.com/ EN-US /库/ system.datetime.ticks(v = vs.110)的.aspx

以上两点要记住:

  1. 它一直追溯到 January 1, 0001
  2. 它基于Nano秒,纪元时间基于毫秒(因子为1000000).

所有这些都表明,理论上这应该代表未来的某个时间点,尽管将来会超远.

那么为什么它不起作用 - 什么时候真的应该!

其根本原因,为什么你实际上最终在你的SO票提到的异常实际上是不是你正在使用蜱(而不是一个时代的时间戳),而是因为微软对JWTs验证理论上限使用他们的框架时,和Owin中间件(稍后会详细介绍,继续阅读).

人们希望:

  1. 真的不应该施加这样的上限; 但也许有安全使用案例需要对门票的到期日施加上限 - 我现在无法想到一个.

  2. 尽管有上面的子弹#1,但是人们希望将来的上限真的很远(如果您既millennial读了这个并且听说过/知道了Y2K的错误,那么额外的学分奖励积分?).然而,MS团队设定的限制实际上即将来临:January 19, 2038 @ 03:14:07 GMT

您可以尝试使用为2038年1月20日设置的exp值验证以下标记来自行测试(2147558400).

{
  "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "SampleToken",
  "nbf": 1507578537,
  "exp": 2147558400,  //<== This timestamp will not work :/
  "iss": "https://api.example.com",
  "aud": "https://example.com"
}
Run Code Online (Sandbox Code Playgroud)

它没有通过验证验证

Microsoft.IdentityModel.Tokens.SecurityTokenException和一个例外消息:IDX10225:生命周期验证失败.令牌缺少过期时间

这不是真的,我提供了一个到期日期,它是一个有效的纪元时间戳(而不是由DateTime.Ticks表示的一个非常大的数字;).

如果您重复相同的测试,通过尝试验证以下令牌,其exp值设置为2038年1月19日00:00:00(2147472000) - 恰好在当前MSFT库的理论限制之前January 19, 2038 @ 03:14:07 GMT,它可以工作.

{
  "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "SampleToken",
  "nbf": 1507578537,
  "exp": 2147472000,
  "iss": "https://api.example.com",
  "aud": "https://example.com"
}
Run Code Online (Sandbox Code Playgroud)

结论:

  1. 微软要么需要:

    一个.延长令牌的到期值的最大日期

    湾 或者,为exp值超过当前最大值时的情况添加另一个Exception消息 - 也许IDX10226: Liftetime validation not possible. Expiration date set too far in the future.

奖励点

好的,在经过这样的细节指出exp索赔的上限之后,不能解释为什么开始有一个上限将是一种耻辱.有人读这篇文章已经发现了上限的原因,因为我已经删除了写入的线索; 如果您已经抓住了它,请告诉您,如果您还没有这里是原因:Microsoft 在对"exp"声明的声明纪元时间戳的值进行比较时隐式使用整数或(Int32)exp.我想将此视为疏忽(有人可能没有完全考虑整个架构,也许没有考虑使用(显式或隐式)Int32与长数据类型(Int64)来存储/比较的含义epoch timestamps.这让我感到愚蠢,这是一个真正的架构决策,选择Int32作为与他们的库的纪元时间戳交互的数据类型 - 但是再次,就像我之前在这篇文章中所说的那样,也许有安全性需要这种强制上限的用例(我不能为我的生活当时想到一个).

仍然不相信,这是Int32可以容纳的最大值:2147483647,根据微软的说法:https://msdn.microsoft.com/en-us/library/system.int32.maxvalue(v = vs.110).aspx .假设2147483647是一个纪元时间戳,猜猜将2147483647转换为日期时你得到的GMT日期/时间是多少?你得到的是:2038年1月19日03:14:07 GMT.您可以使用https://www.epochconverter.com进行转换.

解决方法

  1. 最明显的一个是不创建在2147483647的纪元时间戳之后的任何时间点到期的令牌.在本文撰写的当前时间,微软的owin中间件无法验证(希望他们很快解决这个问题).

  2. 另一种解决方法是编写自己的令牌生命周期验证逻辑.它并不像人们想象的那么复杂,但它确实有助于理解底层的Owin中间件和JW*(JWT,JWE,JWS,JWK等等.Michael B. Jones有一篇有趣的文章JW*在这里:http://www.niso.org/apps/group_public/download.php/14003/SP_Jones_JSON_isqv26no3.pdf)