JWT

JWT

官方网站:jwt

参考博客:Understanding JWT - DEV Community

签名的生成过程

签名的生成过程:

  1. 首先对头部和有效载荷进行编码:通过 Base64Url 编码把它们转换成 URL 安全的格式。
    例如,假设我们有以下的头部和有效载荷:

    • Header(头部):
      {
        "alg": "HS256",
        "typ": "JWT"
      }
      
    • Payload(有效载荷):
      {
        "sub": "1234567890",
        "name": "John Doe",
        "iat": 1516239022
      }
      
  2. 然后将头部和有效载荷拼接在一起:它们被拼接成一个字符串,使用 .(点号)分隔。
    例如:

    base64UrlEncode(header) + "." + base64UrlEncode(payload)
    
  3. 用密钥和签名算法计算哈希:然后,将拼接后的字符串与一个密钥(对于 HMAC 算法来说)一起进行哈希计算。如果是使用 HMAC SHA256 算法,通常的计算方式是:

    HMACSHA256(encoded_header + "." + encoded_payload, secret_key)
    

    其中 secret_key 是服务器和客户端预先共享的密钥。

  4. 最终得到签名:该哈希值作为签名部分,确保 JWT 在传输过程中没有被篡改。

    其实常规的签名就是一个 Hash 函数,发送之前进行 hash,得到一串字符,这一串字符就是签名,我们会把签名跟传输的内容一起发给接收端,接收端收到传输的内容之后,我们用同样的 hash 函数或者说同样的签名算法也算一次,如果得到的一串字符跟发送端发过来的那一串不一样的话,就说明传输的内容被篡改了。
    但是道高一尺魔高一丈,作为篡改数据的人,我在拦截发送方的数据之后,可以在把传输内容换了的时候,用同样的签名算法再算一个新的签名发给服务端啊,对,这就叫中间人攻击,为了避免中间人把签名也改了,发送方和接收方会先约定好一个密钥,签名完之后,用密钥把这个前面的字符串再加个密,如果接收端发现我用密钥无法解密这个签名,或者我把传输的内容签个名,然后用约定好的密钥进行加密,跟发送端发过来那个加过密的签名不一样,接收端就知道传输内容或者签名都被改了。
    这种签名之后再用密钥加密的做法,跟 SSL 证书是一样的,请参考 TSL证书

签名的作用

检查 JWT 是否有效

    {   "sub": "1234567890",   "name": "John Doe",   "iat": 1516239022,   "exp": 1675169032  // 过期时间(UNIX 时间戳) }

其他注意事项:

简介

官网:introduction

什么是 JWT ?

JSON Web 令牌 (JWT) 是一个开放标准 (RFC 7519),它定义了一种紧凑且自包含的方式,用来在各方之间安全地传输信息,这些信息都是 JSON 对象。该信息可以被校验和信任,因为它是数字签名的。可以使用密钥 (使用 HMAC 算法) 或使用 RSA 或 ECDSA 的公钥/私钥对对 jwt 进行签名。

虽然 jwt 也可以加密以在各方之间提供保密性,但我们将重点关注已签名的令牌(也就是主要以签名的方式处理 JWT)。签名令牌可以验证其中包含的声明的完整性,而加密令牌则对其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时,签名还证明只有持有私钥的一方是对其进行签名的一方。

关于加密和签名的区别,请看《非对称加密》的 签名和加密的不同 小节

JWT 主要用于什么场景?

请注意,使用已签名的令牌的时候,令牌中包含的所有信息都将公开给用户或其他接收方的,即使他们无法更改它。这意味着您不应该在令牌中放入机密信息

优点和缺点:

优点:

缺点:

SpringBoot 整合 JWT

参考教程:

java - 深入总结SpringBoot整合JWT,这应该是全网讲的最通俗易懂的了 - 架构人生 - SegmentFault 思否

Springboot整合jwt实现token登录验证功能 - 掘金

过程也很简单,引入相关依赖,添加登录拦截器即可。

Spring Security 整合 JWT

整合SpringSecurity和JWT实现登录认证和授权 - 掘金

https://mp.weixin.qq.com/s/KGy02byw74P-xZRK5wzXDw

用的最多。

关于 cookie 的相关解析,请看《会话跟踪技术.txt》

JWT 的 token 可以放在 cookie 中或者放在 header 中,具体取决于您的应用程序需求和设计选择。
放在 cookie 中的优点:

放在 header 中的优点:

根据实际情况,您可以选择将 JWT 放在 cookie 中或者放在请求头中。通常,对于 API 身份验证,将 JWT 放在请求头中更为常见和推荐。而对于传统的 Web 应用程序,将 JWT 放在 cookie 中可能更为方便。无论您选择哪种方式,请确保在处理 JWT 时采取适当的安全措施,例如对 JWT 进行签名和验证,并设置适当的过期时间

注意,如果通过 HTTP 头发送 JWT 令牌,则应该尽量防止它们变得太大。有些服务器不接受超过 8KB 的消息头。如果您试图在 JWT 令牌中嵌入太多信息,比如包含所有用户的权限,那么您可能需要一个替代解决方案,比如 Auth0 Fine-Grained Authorization.

而且放到请求头中也不会存在跨域问题

JWT 与密码的使用场景的区别

JWT 相比密码,区别在于,JWT 是临时生成的,在有效期内总是有效,超过有效期需要重新生成;而密码是用户设置的,在用户主动修改之前总是有效的,有效期由其他策略控制,但通常都很长,用户修改密码后旧密码立即失效。所以,如果使用 JWT 做 session 保持,那么在用户修改密码之后,修改密码之前登录并签发的 JWT 不会立即过期,所有持有 JWT 的人依旧可以继续访问。因为 JWT 本身做不到主动失效,相当于 JWT 是用户的一个不受用户控制的“密码”,

如果你的系统支持 JWT 续期,那么一旦 JWT 泄漏,用户将无法找回账号,因为第三方可以拿着截获的 JWT 进行无限续期,用户改密码都不行的。解决办法就是,在用户退出,或是修改密码的时候,使此用户的所有 JWT 立即失效。前面说过,JWT 一旦生成,在有效期之前总是有效的,是不受控制的……所以为了使 JWT 立即过期,服务端必须记录所有生成的有效的 JWT,在使用 secret 校验的时候检查 JWT 是否在有效 JWT 列表中,如果不在,那么即便是 JWT 有效也拒绝认证。这样,只要在用户退出登录,或是修改密码的时候,删除服务端此用户的所有 JWT 记录即可。

但是,到了这个模式,如果服务端要支持用户退出,则必须要记录 JWT 的有效性,而记录 JWT 有效性,不如直接记录一个安全随机数……也就是说,JWT 本身并不是用来做 session 保持的,session 保持还是用服务端生成的一段安全随机数来进行比较好。而 JWT 的使用场景,通常是在服务切换的时候,用作身份令牌的。比如从 A 服务跳转到 B 服务,要带过去一些信息,这时候就可以用 JWT 来实现了,JWT 的有效期通常设置为不超过 5 秒。

JWT 安全性问题

在进行身份验证的时候,客户端(一般是浏览器)是不需要对 JWT 进行解密的,登录成功之后只需要在每次请求的时候带上 JWT 即可,此外,JWT 也是不能泄露的,因为如果别人拿到了这个 JWT,那么别人就可以冒充你,因为服务端只认 JWT,只要 JWT 是有效的,就会通过服务端的验证。

因此,将 JWT 保存在 cookie 中不一定是一个好主意。

如果泄露了 JWT 怎么办?

泄露的 JWT 与泄露的密码相同。您应该遵循与密码泄露相同的步骤。这可能包括

如何检测 JWT 泄露

如何避免 JWT 令牌 token 泄露恶意使用

保护 JWT 本身就是一项复杂的任务,如果您关心用户的数据,则需要付出很大的努力。这就是为什么总是建议您将处理身份验证的任务委托给外部服务,如 Auth0 或 Okta 或 FusionAuth。对于象征性的收费,这些服务将处理您的所有身份验证问题。