应用场景#
互联网服务中最常见的功能便是用户认证,比如登陆了某个网站后下次就可以自动登录。
由于 HTTP 是无状态协议,因此使用 cookie 来进行用户认证。
1、用户向服务器发送用户名和密码。
2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id,写入用户的 Cookie。
4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。plaintext但是问题在于,这里的 session 信息保存在哪里?
-
保存在持久层(数据库),服务收到请求后,向持久层请求数据。
- 缺点:工程量大
-
保存在客户端,每次请求时发给 session
JWT,即 Json Web Token 就是第二种方案。
现实应用#
传统的导入和配置不再赘述,主要讲一些扩展。
缺陷#
如果黑客截获了 JWT,那么其就可以在令牌过期前冒充用户,进行一切合法的操作。
这也是所有基于 Token 机制所面临的共同安全挑战。
为什么 JWT 泄漏后可以被冒充?
-
无状态性
- JWT 被生成后,后端服务器不会在内存或 Redis 中存储其状态
- 后端只通过 Token 的签名来验证其是否有效、过期,而无法知道其是否泄漏或被调用
-
自包含性
- JWT 内部包含了用户信息(比如苍穹外卖中的
user_id) - 黑客只需要将 JWT 包含在 HTTP 请求头中,拦截器看到 Token 是合法的,就会认为这个请求是用户
user_id发出的
- JWT 内部包含了用户信息(比如苍穹外卖中的
对于基于 Session 的认证,服务器会在内存或 Redis 中存储 Session ID。如果用户密码泄漏或检测到异地登录,服务器就可以直接删除这个 Session ID,用户就会立即掉线。
但 JWT 是无状态的,即:
- 无法注销:JWT 的注销只是前端删除了本地存储的 Token。Token 本身依然有效,直到过期
- 无法吊销:在 Token 有效期内,即使服务器发现该 Token 被盗,也无法立刻使其实效
3.2 补救#
对于 Web 应用,可以采取以下几种措施来降低 JWT 泄漏的风险:
-
设置极短的有效期:如果用户体验要求高,可以引入 Refresh Token 机制
-
Access Token 设置 1 小时有效
-
额外签发一个 Refresh Token,设置 7 天有效,用于在 Access Token 过期后安静的换取新的 Access Token,减少用户登录的次数
-
-
实现 Token 黑名单机制
-
做法:将指定用户的 JWT ID 存入 Redis 黑名单中,并设置黑名单过期时间与 JWT 有效期一致
-
校验流程:拦截器在校验 JWT 签名和有效期时,会额外查询其 ID 是否包含在 Redis 黑名单中
-
如果 Token 被加入黑名单,其就无法在请求服务
-
-
增强传输安全性(HTTPS)
- 使用更安全的 HTTPS 进行加密传输,降低了 JWT 被截获的风险