Cookie,Session,JWT
前言
由于早期的网页被设计出来只是为了满足人们浏览网络资源的需求,几乎没有交互,所以HTTP在设计之初就是无状态的,无法携带信息。随着互联网的发展,为了满足人们对于网络交互的需求,需要一种技术来保存用户信息,用于登录认证等。
目前常见的技术便是 Cookie,Session,JWT 。
Cookie
Cookie存储于客户端(浏览器),当用户访问一个页面时,客户端将用户填好的账号,密码,验证码等信息发送给服务器,服务器验证无误后会将用户信息保存在Cookie中,返回给客户端。
客户端(浏览器)在每次向服务器发起请求时都携带这个Cookie,服务器根据Cookie中的用户信息便可以识别出当前用户。
优点
- Cookie存储在客户端,服务器没有内存压力
- 服务器可拓展性强,Cookie存储在客户端,当请求到不同的服务器时依旧可以识别身份
- 由于Cookie存储于客户端(浏览器)中,用户可以自由清除
- 网站往往会在Cookie中缓存用户基本信息,可以在某些时候自动帮助用户填写一些基本信息
- 在Cookie存储一些用户信息有利于网站个性化用户体验(例如个性化广告)
缺点
- 必须要客户端开启Cookie
- 当用户信息过多时,客户端效率会降低,因为内存占用过多
- 存储在Cookie中,会完全暴露于网络环境中,安全性太低,任何人都可以读写
- CSRF(Cross Site Request Forgery),易受跨站点请求伪造攻击。由于Cookie存储了你的用户信息,如果别人仿造了你的Cookie,那么就可以用你的身份来向服务器发起请求,服务器成功识别Cookie保存的你的用户信息,便可以向他人提供对你不利的服务。(例如在银行网站中拿到你的Cookie后向服务器发起转账请求)
Session
Session存储于服务器端,当用户访问一个页面时,客户端将用户填好的账号,密码,验证码等信息发送给服务器,服务器验证无误后会生成一个用于标识用户身份的sessionID,同时创建一个Session来维护用户信息,并且创建一个Cookie,将sessionID存在Cookie中,返回给客户端。
此后每次客户端向服务器发起请求时都在Cookie中带上这个sessionID,服务器根据sessionID便可识别出需要处理哪个用户的信息。
优点
- 客户端(浏览器)Cookie中只需要存储sessionID,快捷高效
- 较为灵活,服务器可以定义session的过期时间等等,客户端无法控制
缺点
- Session通常与Cookie混合使用,如果用户关闭了Cookie就无法实现。解决方案:
- 将sessionID存在url中,但这样安全性更低,前后端代码复杂度也会上升
- 将sessionID放在请求体中,前后端代码复杂度提高,不利于维护
- 同样无法避免CSRF。如果他人在Cookie中拿到了你的sessionID便可以伪造成你。
- 如果部署了多台服务器,当负载均衡机制将请求分配到其它服务器时,会因为sessionID无法匹配而识别用户失败。有如下常见处理方案:
- 当产生一个Session时便在每台服务器上同步,会产生大量的服务器资源浪费
- 通过特定算法将请求固定分配到一台服务器上,但是当这台服务器出问题时就无法处理用户请求
- 最常用的是将所有的Session信息统一存储在一个地方,例如Redis,当请求到服务器时,服务器向Redis发起请求获取用户Session。注意部署Redis集群来提高抗灾能力。
- 整合Spring Session实现会话(Session)共享合同步。
JWT
JWT(JSON Web Token)不依赖与Session,一般也不使用Cookie存储,而是存储在localStorage中,可以有效避免CSRF。
JWT由三部分组成:
- Header : 描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型。
- Payload : 用来存放实际需要传递的数据,默认不加密,不宜存储私密信息
- Signature(签名):服务器通过 Payload、Header 和一个密钥(Secret)使用 Header 里面指定的签名算法生成
当用户访问一个页面时,客户端将用户填好的账号,密码,验证码等信息发送给服务器,服务器验证无误后会生成一个用于标识用户身份的JWT,返回给客户端,客户端一般将JWT存在localStorage中。
此后每次客户端向服务器发起请求时都在请求头中带上这个JWT,服务器根据JWT便可识别出需要处理哪个用户的信息。
优点
- 安全性较高
- 服务器只需存储密钥,可扩展性强
- JWT一般存于localStorage(也可存于Cookie),没有CSRF风险
缺点
- 前后端代码复杂度较高
- 密钥泄露,全部完蛋
- PayLoad默认不加密,不宜存储私密信息
- 移动端友好(移动端没有Cookie)
- 由于JWT存在客户端,服务器没有其它逻辑,无法简单让JWT失效(退出登录,注销等)。有以下处理方法:
- 在数据库或Redis中维护JWT状态,每次请求先从数据库中查看JWT是否有效。会提高代码复杂度
- 服务器给JWT设置有效期。但是有效期为多少以及什么时候更新有效期,难以把握
- 设置备用JWT,当现JWT快过期时就启用备用JWT,同时再生成一个备用JWT。同样难以把握,备用JWT如果提前泄露,不利于用户安全
- 将JWT过期时间设置在用户休眠期间。对于大型网站不友好