Web身份认证 --- JWT Token

什么是JWT

  • JWT,全称为JSON Web Token,是一种开放标准(RFC 7519),用于在网络应用环境间安全地传输信息。
  • 它本质上是一个经过数字签名的JSON对象,能够携带并传递状态信息(如用户身份验证、授权等)
  • JWT由 Header + Payload + Signature三部分组成, 并经过Base64Url编码之后使用 (注意编码不是加密)
  • 注意在token机制中不一定非要使用JWT,任何包含认证信息的token都可以,只不过目前唯一流行的是JWT
    在这里插入图片描述

Header

  • JWT 的头部通常由两部分组成,分别是令牌类型(typ)和加密算法(alg)。一般情况下,头部会采用 Base64 编码。
{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

  • JWT 的载荷也称为声明信息,包含了一些有关实体(通常是用户)的信息以及其他元数据。通常包括以下几种声明:
  • Registered Claims:这些声明是预定义的,包括 iss(发行者)、sub(主题)、aud(受众)、exp(过期时间)、nbf(生效时间)、iat(发布时间)和 jti(JWT ID)等。
  • Public Claims:这些声明可以自定义,但需要注意避免与注册声明的名称冲突。
  • Private Claims:这些声明是保留给特定的应用程序使用的,不会与其他应用程序冲突。
  • 注意:Payload中一定不要存放敏感或重要信息,如密码等
{
  "sub": "666666",
  "name": "warriors",
  "admin": true
}

Signature

  • JWT 的签名是由头部、载荷和密钥共同生成的。它用于验证 JWT 的真实性和完整性。一般情况下,签名也会采用 Base64 编码。
    例如,如果要使用 HMAC SHA256 算法,将按以下方式创建签名:
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

JWT完整流程

  • 假设你现在有一个应用,需要用户登录后获取访问权限。

用户登录

  • 用户在登录页面输入用户名和密码,点击登录。服务器接收到登录请求并验证用户的凭证。

生成JWT

  • 如果用户的凭证(账号密码)正确,服务器将生成一个JWT。假如服务器将生成的JWT为:
  • eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • 让我们详细分解这个JWT的生成过程,一共三个部分,每个部分被点号(.)截断

Header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

  • base64url解码一下得到
{
	"alg": "HS256",
	"typ": "JWT"
}
  • 这个头部表示我们将使用HMAC SHA-256算法进行签名,并且这是一个JWT。

Payload: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

  • base64url解码一下得到
{
	"sub": "1234567890",
	"name": "John Doe",
	"iat": 1516239022
}
  • 这个负载部分包含了一些声明,比如用户ID(sub)、用户名(name)和签发时间。

Signature: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

  • 第三部分签名的生成是由第一部分和第二部分组成的
  • 我们使用密钥(secret)来生成签名。签名是使用以下方法生成的:
  • 将编码后的Header和Payload用点号(.)连接在一起:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
  • 使用HMAC SHA-256算法和密钥secret对上述字符串进行签名:
header_payload = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
secret = "secret"
signature = hmac.new(secret.encode(), header_payload.encode(), hashlib.sha256).digest()
signature_base64 = base64.urlsafe_b64encode(signature).rstrip(b'=').decode()
print(signature_base64)
  • 生成的第三部分签名是:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • 最后,将编码后的Header、Payload和生成的Signature用点号(.)连接在一起,形成完整的JWT:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

返回JWT

  • 服务器将生成的JWT返回给客户端。客户端可以将JWT存储在本地存储(Local Storage)或Cookie中。

携带JWT进行请求

  • 在用户登录后的每次请求中,客户端会在请求头中携带JWT,例如:
  • Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

服务器验证JWT

  • 服务器接收到请求后,会验证JWT的签名是否正确。验证过程如下:
  • 从JWT中提取出header和payload部分。
  • 使用同样的签名密钥和header中的算法,重新生成签名。
  • 将重新生成的签名与JWT中的签名进行比较,如果相同,则验证通过。

响应请求

  • 如果JWT有效且未过期,服务器处理请求并返回响应。

JWT攻防

常见攻击方法

  • 暴力破解签名密钥:攻击者可以使用暴力破解的方法猜测JWT的签名密钥。如果签名密钥比较弱,这种攻击可能会成功。
  • 算法替换攻击:如果服务器在验证JWT时不严格检查头部的alg字段,攻击者可以将alg字段改为none,绕过签名验证。
  • 伪造Token:如果服务器使用对称加密算法(如HS256),并且密钥泄露,攻击者可以使用密钥伪造有效的JWT

防御措施

  • 使用强密钥:确保签名密钥足够强,难以被暴力破解。
  • 严格验证算法:在服务器端严格验证alg字段,拒绝none算法。
  • 使用非对称加密:使用非对称加密算法(如RS256),即使公钥泄露,攻击者也无法伪造JWT。
  • 定期更换密钥:定期更换签名密钥以增加安全性。
  • 设置适当的过期时间:设置合理的JWT过期时间,减少被盗用的风险。

JWT 如何退出登录

JWT一旦发出,不能撤回,所以在有效期内会一直有效,常见退出方法有三种

  • Simply remove the token from the client
  • Create a token blacklist
  • Just keep token expiry times short and rotate them often

JWT的续签

  • JWT在使用中一般遵循OAuth2.0的标准,OAuth2.0中的续签通常使用“双令牌(access_token, refresh_token) 续签”
  • 注意 access_token和refresh_token是OAuth2规范的内容,不是jwt规范的部分

访问令牌(Access Token)

  • 用途:访问令牌是一个短期的令牌,用于授权第三方应用访问受保护的资源。每次访问受保护的资源时,第三方应用需要在请求头中携带这个令牌。
  • 有效期:访问令牌通常有一个较短的有效期,可能是几分钟到几小时不等。这是为了减少令牌被盗用的风险。
  • 格式:访问令牌通常是一个字符串,可以是 JWT(JSON Web Token)格式,也可以是其它格式。

刷新令牌(Refresh Token)

  • 用途:刷新令牌用于获取新的访问令牌。当访问令牌过期时,客户端可以使用刷新令牌向授权服务器请求新的访问令牌,而不需要再次通过用户的授权。
  • 有效期:刷新令牌的有效期通常比访问令牌长得多,可以是几天、几周甚至更长时间。
  • 安全性:由于刷新令牌的有效期较长,应该妥善保护,避免泄露。一般来说,刷新令牌不应该在前端应用中存储,而应存储在服务器端

为什么需要两个token

首先确认一点: token使用的次数越多被窃取概率越大,过期时间越长也就越危险

  • 一个token的续签方法: 假设现在只有一个access token,因为使用次数很多(每次Api调用都会用到)并且token无法被设置为失效, 所以access token的过期时间需要被设置的很短,这样即使被token盗,损失也可以降到最低.
  • 方法一: token过期之后,用户重新输入账号密码拿到新的access token.
  • 缺点:因为access token过期时间很短,用户需要频繁输入账号密码,很影响使用.
  • 方法二:当服务器收到请求之后,计算token剩余有效时间,如果小于一个阈值,则颁发新access token.
  • 缺点:如果用户在阈值之内没有进行api调用,则还是需要重新输入账号和密码,影响使用
  • 缺点:如果access被盗用,则盗用者还是可以通过被盗用的access token进行续签,拿到新的token.

使用两个token续签:

  • OAuth2定义了资源服务器授权服务器,第一次认证向授权服务器提交用户名和密码获得两个token,然后访问资源服务器获取资源使用access_token
  • 当access_token有效期失效的时候,前端使用这个refresh_token请求授权服务器换取新的acceess_token来保证接口的正常请求, 这样可以做到用户无感知续签
  • 这样即使access token被盗用,access token的过期时间设置的很短,损失也可以降到最低.
  • 而refresh token使用次数少,保存在数据库中,被盗风险小
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值