美文网首页
JWT 中 iat 字段的坑

JWT 中 iat 字段的坑

作者: 舌尖上的大胖 | 来源:发表于2024-10-16 12:03 被阅读0次

一、常规校验

在 JWT 的使用中,基于 JWT 的 SDK 可以做基础的有效性校验(不包含业务规则)。

这些校验一般包括:

  • 生效时间(Payload 中的 nbf 字段,Not Before)
  • 过期时间(Payload 中的 exp 字段,Expiration Time)
  • 签名合法性

二、iat 字段的坑

在 Payload 部分,有个 iat 字段(Issued At:签发时间)。在我们的理解中,这个字段只表示签发时间,是个标记,并不参与校验。但实际上并不一定是这样的。

1、RFC 文档中的描述

链接:JSON Web Token (JWT)

4.1.6. "iat" (Issued At) Claim

4.1.6. "iat" (Issued At) Claim
The "iat" (issued at) claim identifies the time at which the JWT was
issued. This claim can be used to determine the age of the JWT. Its
value MUST be a number containing a NumericDate value. Use of this
claim is OPTIONAL.

这里表述了如下几个意思:

  • 字段作用:表示 JWT 的颁发时间
  • 可以用于确定 JWT 的时效性
  • 此字段可选

但是有一点文档中没有明确:即当这个字段有值时,其值是否会影响 JWT 的有效性。

2、JWT 库的实现

Java 项目中,使用较多的 JWT 库是 auth0/java-jwt。其最新版本(4.4)的校验实现部分是这样的:

private void addMandatoryClaimChecks() {
    long expiresAtLeeway = this.getLeewayFor("exp");
    long notBeforeLeeway = this.getLeewayFor("nbf");
    long issuedAtLeeway = this.getLeewayFor("iat");
    this.expectedChecks.add(this.constructExpectedCheck("exp", (claim, decodedJWT) -> {
        return this.assertValidInstantClaim("exp", claim, expiresAtLeeway, true);
    }));
    this.expectedChecks.add(this.constructExpectedCheck("nbf", (claim, decodedJWT) -> {
        return this.assertValidInstantClaim("nbf", claim, notBeforeLeeway, false);
    }));
    if (!this.ignoreIssuedAt) {
        this.expectedChecks.add(this.constructExpectedCheck("iat", (claim, decodedJWT) -> {
            return this.assertValidInstantClaim("iat", claim, issuedAtLeeway, false);
        }));
    }
}

从这里可以看到:

  • iat 字段通过配置来决定是否参与到校验,默认是参与校验的(我估计是为了与旧版兼容,稍后贴旧版代码)
  • 如果 iat 字段参与校验,其内容不允许是当前时间的未来时间

但是在旧版(3.x)版本中,iat 字段是必须参与校验的:

private void verifyClaims(DecodedJWT jwt, Map<String, Object> claims) throws TokenExpiredException, InvalidClaimException {
    for (Map.Entry<String, Object> entry : claims.entrySet()) {
        switch (entry.getKey()) {
            case PublicClaims.AUDIENCE:
                //noinspection unchecked
                assertValidAudienceClaim(jwt.getAudience(), (List<String>) entry.getValue());
                break;
            case PublicClaims.EXPIRES_AT:
                assertValidDateClaim(jwt.getExpiresAt(), (Long) entry.getValue(), true);
                break;
            case PublicClaims.ISSUED_AT:
                assertValidDateClaim(jwt.getIssuedAt(), (Long) entry.getValue(), false);
                break;
            case PublicClaims.NOT_BEFORE:
                assertValidDateClaim(jwt.getNotBefore(), (Long) entry.getValue(), false);
                break;
            case PublicClaims.ISSUER:
                assertValidStringClaim(entry.getKey(), jwt.getIssuer(), (String) entry.getValue());
                break;
            case PublicClaims.JWT_ID:
                assertValidStringClaim(entry.getKey(), jwt.getId(), (String) entry.getValue());
                break;
            case PublicClaims.SUBJECT:
                assertValidStringClaim(entry.getKey(), jwt.getSubject(), (String) entry.getValue());
                break;
            default:
                assertValidClaim(jwt.getClaim(entry.getKey()), entry.getKey(), entry.getValue());
                break;
        }
    }
}

三、iat 字段参与校验带来的影响

我们一般习惯添加 iat 字段来记录颁发时间,并且这个时间基本都会取当前时间。

假想以下场景:

  • A、B 两台主机上的服务交互协作

  • A 主机上的服务颁发 JWT,由 B 主机上的服务校验

  • B 主机的时钟比 A 主机慢一点

如果 A 颁发 JWT 时以自己当前的时间写入了 iat 字段,本意只是标识颁发时间。但 B 校验时,iat 字段参与了校验,由于 B 的时钟慢,对于 B 来说,iat 字段中的时间是个未来时间,所以会认为 JWT 不合法,从而导致校验失败。

这问题排查起来简直是觉得无厘头。

四、解决方案

1、没有特别需要,尽量不写入 iat 字段,以规避不确定性。因为一般 JWT 的 SDK 文档中,也不会写这么细。没必要找麻烦;

2、如果自己想做个标识记录下颁发时间,可以使用一个自定义字段记录;

3、如果使用的 SDK 支持指定 iat 字段是否参加校验(如 auth0/java-jwt ),那么尽量在执行校验时,忽略这个字段,不对这个字段进行校验。如果使用的 SDK 不支持自己定义这个选项(如:Auth0 低版本的 JWT 库或者其他某些库),就只能在颁发 JWT 时,通过避免写入 iat 字段来规避这个问题了。

另:这里没有广泛对各种库的实现进行验证,只是发现这个坑先抛出来,大家有验证结果可以补充。

(完)

相关文章

  • mysql 迭代查询所有上级

    表结构为 坑点,表中的主键除id,pid字段,其余字段不能为主键(不明所以,这是目前测出来的坑)即目前表中,只要设...

  • python进阶

    测试发现iat方法消耗时间只有 self.frm.iloc[x,y] = now_value方法的3% 坑: 某一...

  • JWT认证实务

    先行占坑。 JWT = header + payload + signature Claims:Registere...

  • 脱壳经验2

    IAT在内存中和在文件中的特征?IAT在内存中是一个函数地址数组,在文件是是一个RVA数组 重定位的原理是什么?重...

  • Laravel5 JWT

    在使用laravel集成的JWT的过程中遇到的坑 laravel官方的集成简介 环境:laravel5.3+win...

  • Go踩过的坑之gorm外键关联字段null值无法插入

    Go踩过的坑之gorm外键关联字段无法插入 先知 在外键字段 的gorm标签中添加缺省==default:'gal...

  • jwt 在微服务中应用

    jwt token jwt 在api 方式中表中的token生成,验证以及获取jwt解密后携带的用户信息 jwt ...

  • JWT Authentication in Django

    Django中的JWT认证 本教程将介绍JSONWeb令牌(JWT)以及如何在Django中实现JWT身份验证。 ...

  • Laravel5.4 Jwt 1.0 beta 配置

    先说我走过的坑: 我用了Laravel5.4,require了jwt的0.5.11版本,简直被坑哭了。 前期一帆风...

  • decode jwt token in python

    本文解决jwt token 在 python中decode报错的问题,至于JWT是什么,见 jwt.io deco...

网友评论

      本文标题:JWT 中 iat 字段的坑

      本文链接:https://www.haomeiwen.com/subject/fqsxdjtx.html