JWT:原理、机制与实践

一、前言

在当今的网络应用开发中,用户认证是一个至关重要的环节。随着技术的发展,传统的基于Session的认证方式逐渐暴露出一些问题,如跨域限制、服务器性能瓶颈等。而JSON Web Token(JWT)作为一种新兴的认证解决方案,以其无状态、可扩展性强、易于跨域等优势,受到了广泛的关注和应用。

二、JWT基本介绍

JWT(JSON Web Token)是一种开放标准(RFC 7519),它允许在各方之间安全地将信息作为JSON对象传输。JWT本质上是一个字符串,由三部分组成:头部(Header)、负载(Payload)和签名(Signature),各部分之间用英文的“.”分隔。其具有如下特点:

  1. 无状态:服务器无需存储客户端的会话信息,所有信息都包含在Token中,减轻了服务器的存储压力。
  2. 自包含:Token中包含了用户的相关信息,服务器可以通过解析Token获取用户信息,无需查询数据库。
  3. 跨域支持:与基于Cookie的认证方式不同,JWT不依赖Cookie,因此在跨域场景下不会受到浏览器同源策略的限制。
  4. 安全性:通过加密算法对Token进行签名,确保了Token在传输过程中的完整性,防止被篡改。

三、JWT的原理机制

(一)组成

  1. 头部(Header):通常由两部分组成,alg表示签名算法,如“HMAC SHA256”或“RSA”;typ表示令牌的类型,即JWT。例如:
{
  "alg": "HS256",
  "typ": "JWT"
}

将上述JSON对象使用Base64 URL算法转换为字符串,得到头部编码。

  1. 负载(Payload):包含声明,声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:注册声明、公共声明和私有声明。例如:
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
● Registered claims : 这里有一组预定义的声明,它们不是强制的,但是推荐。比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等。
● Public claims : 可以随意定义。
● Private claims : 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明。

这段文本是对JWT(JSON Web Token)中不同类型声明的解释说明。主要内容包括:

Registered claims(注册声明)

这是一组预定义的声明。它们不是强制要求的,但被推荐使用。
一些常见的例子包括:
iss(Issuser):代表这个 JWT 的签发主体;
sub(Subject):代表这个 JWT 的主体,即它的所有人;
aud(Audience):代表这个 JWT 的接收对象;
exp(Expiration time):是一个时间戳,代表这个 JWT 的过期时间;
nbf(Not Before):是一个时间戳,代表这个 JWT 生效的开始时间,意味着在这个时间之前验证 JWT 是会失败的;
iat(Issued at):是一个时间戳,代表这个 JWT 的签发时间;
jti(JWT ID):是 JWT 的唯一标识。

Public claims(公共声明)
可以随意定义。这意味着开发者可以根据自己的需求来创建和使用这些声明,只要确保这些声明的名称不会与注册声明冲突即可。它们是公开的,用于在各方之间传递自定义信息。

Private claims(私有声明)
用于在同意使用它们的各方之间共享信息。这些声明不是注册的或公开的,具有一定的私密性,只在参与的各方之间使用,以满足特定的业务或应用需求。

对负载部分也进行Base64 URL编码。

  1. 签名(Signature):为了创建签名部分,需要采用编码后的头部、编码后的负载和一个密钥。密钥通常是通信双方提前协定的,对于HASH签名方式,使用一个字符串即可。例如:
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

如采用非对称加密算法RSA,采用公钥与私钥进行加密和解密,从而不仅可以防止篡改,还是确定发生方的身份。

实际应用中,大多采用的是Hash方式,简单易用。

(二)工作流程

  1. 生成令牌
    • 用户通过用户名和密码向服务器发送登录请求。
    • 服务器验证用户身份信息,验证成功后,使用JWT算法,将包含用户信息的数据作为JWT的Payload,将其与JWT Header分别进行Base64编码拼接后签名,生成一个JWT Token。
  2. 传输令牌
    • 服务器将生成的JWT Token返回给客户端,客户端通常会将Token存储在localStorage或cookie中。
    • 当客户端之后向服务器发送请求时,需要在HTTP请求头中的Authorization字段中携带JWT Token,格式为“Bearer ”。
  3. 验证令牌
    • 服务器接收到带有JWT Token的请求后,提取Token中的头部、负载和签名信息。
    • 使用相同的密钥和算法对头部和负载进行签名,并比较生成的签名与Token中的签名是否匹配。如果匹配,则Token有效;否则,拒绝请求。
    • 服务器还会验证负载中的声明,例如检查Token是否过期、发行者是否可信等。

四、使用JWT的注意事项

  1. 安全性
    • 使用强密钥和算法:选择高强度的加密算法和密钥,防止Token被破解。
    • 防止信息泄露:避免在JWT中存储敏感信息,如用户的密码等。因为JWT默认情况下是未加密的,只是Base64编码,所以任何人都可以解读其内容。
    • 采用HTTPS协议:在传输过程中使用HTTPS协议,确保数据在传输过程中的安全性,防止中间人攻击。
    • 防范XSS攻击:由于JWT通常存储在客户端,如localStorage或cookie中,容易受到XSS攻击的威胁。因此,需要采取措施防范XSS攻击,如对用户输入进行严格过滤和转义等。
    • 防御重放攻击:可以通过在Token中添加时间戳、随机数等信息,以及在服务器端维护一个已使用的Token列表等方式来防御重放攻击。
  2. 令牌过期与刷新机制
    • 在负载(Payload)中加入exp(过期时间)字段,定义令牌的生命周期。当令牌过期后,接收方应拒绝处理该令牌。
    • 实现刷新机制,允许客户端在访问令牌过期后,使用刷新令牌获取新的访问令牌,而无需用户重新输入用户名和密码。但要注意刷新令牌的安全性、限制刷新次数以及设置合理的过期时间。
  3. 单点登录(SSO)的风险
    • 在单点登录场景下,如果一个用户的JWT被盗用,可能会导致多个系统受到影响。因此,需要采取额外的安全措施来保护单点登录系统。
  4. 令牌撤销机制
    • 由于JWT是无状态的,服务器无法直接撤销一个有效的JWT。可以采用黑名单机制,将已撤销的Token记录在黑名单中,当客户端请求时,服务器检查Token是否在黑名单中。
    • 实际应用中有一种相对便捷的处理方式,即不采用统一的密钥,而是将用户的密码作为密钥,当发现令牌被非法获取和使用时,可以通过修改用户密码这一常规操作,实现令牌的撤销。
  5. 存储和传输的安全性
    • 如果将JWT存储在localStorage中,需要注意localStorage的安全性较低,容易受到XSS攻击。可以考虑使用HttpOnly和Secure标志设置的cookie来存储JWT,以提高安全性。
  6. 及时更新库和依赖
    • 关注JWT相关库和依赖的更新,及时修复已知的安全漏洞。

五、常见问题

  1. 如何处理JWT过期问题?
    • 客户端在每次发送请求时,可以先检查JWT是否过期。如果过期,则尝试使用刷新令牌获取新的访问令牌。
    • 服务端在接收到请求时,也会验证JWT的过期时间。如果过期,返回相应的错误信息,客户端根据错误信息提示用户重新登录或自动刷新令牌。
  2. JWT是否适合存储大量数据?
    • JWT不适合存储大量数据,因为Token的大小会增加,导致每次请求的HTTP头信息变大,影响性能。JWT主要用于存储用户身份信息和一些必要的声明,而不是大量的业务数据。
  3. 如何防止JWT被篡改?
    • JWT通过签名来确保数据的完整性。只有使用正确的密钥和算法对JWT进行签名验证,才能确保JWT未被篡改。因此,必须确保密钥的安全性,防止密钥泄露。
  4. JWT在分布式系统中的优势?
    • JWT在分布式系统中具有明显的优势。由于其无状态的特点,各个服务节点无需共享会话信息,减少了服务之间的耦合性,提高了系统的可扩展性。

如果您在阅读本文时获得了帮助或受到了启发,希望您能够喜欢并收藏这篇文章,为它点赞~

请在评论区与我分享您的想法和心得,一起交流学习,不断进步,遇见更加优秀的自己!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行者无疆1982

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值