cookie,session和token的辨析

因为HTTP协议是无状态的,只能分辨请求而不能分辨会话,因此为了实现会话追踪(即在一次会话的不同请求间共享数据),会话跟踪技术应运而生。
传统的基于客户端的cookie技术和基于服务端的session技术的主要功能是实现一次会话的不同请求间数据共享。在实际工程中,往往会使用cookie作"记住用户名和密码"这一业务实现。session用于实现"身份验证"这一业务功能。
token技术主要是为了身份验证,并不是为了同一会话的不同请求间数据共享。

会话跟踪技术

客户端会话跟踪技术cookie

将数据存在客户端的内存中,以后每次请求都携带cookie访问,cookie放在请求头中。
基本使用步骤

  1. 服务器收到客户端请求,创建cookie对象,向其中存入需要共享的数据(例如账号密码)。然后将cookie放入响应头中。
  2. 客户端收到信息,将cookie存入浏览器内存中,以后每次访问服务器时携带,放在请求头中。
  3. 服务器可以取得cookie中的值,用于请求间数据共享。
  4. 浏览器端也可以读取内存中的cookie值供自己页面使用。例如,实现记住账号密码功能,将cookie值取出自动填充到页面。

服务端会话跟踪技术session

将数据保存在服务端,同时借助cookie保存其指针sessionId,每次cookie携带此指针,用于定位存储存储在服务端的session

基本使用步骤

  1. 服务器使用reuqest.getSession方法获得session对象,在session中存入共享数据。之后底层将sessionId存入cookie中发送给客户端。

  2. 当客户端收到存有sessionId的cookie后,保存在浏览器内存中。以后每次访问服务器时携带在请求头中。

  3. 服务器再次收到携带有sessionId的请求后,使用reuqest.getSession方法获得session对象,在session中取出使用共享数据。实现了数据共享。

cookie和session的对比

cookie session
存储位置 客户端 服务端(但是存sessionId需要借助session实现)
安全性 不安全 安全
数据大小 最大3KB 无限制
存储时间 可设置长期(默认与浏览器进程一致) 默认服务器内存30分钟
对服务器性能影响 不影响 占用服务器内存资源

按照身份验证划分为两大类:

token设计之初就是为了实现身份验证。而session的方式(基于cookie)设计的目的是共享数据,因此也能实现身份验证的功能。

传统的身份验证(cookie和session)

基本步骤:

  1. 客户端在请求体中携带用户名和密码,即username和password,发送请求给服务器端。
  2. 服务器端根据username到数据库查询password,查询验证成功,将username存入session中,并且将此session对象的sessionId放入cookie中,cookie放入响应头中,发送给客户端。
  3. 客户端接收到cookie,将其存入浏览器内存中。下次发送请求时,携带此cookie在请求头中一起发送给服务器。
  4. 服务器接收到携带cookie的请求后,根据cookie中的sessionId找到session对象,与请求的username对比,若相等,则身份验证成功。

类似于客户端通初次验证后获得了一张通行证,可以带着通行证去访问服务器。
存在的问题:

  1. 消耗服务器内存。为了验证身份,浪费了大量的服务器内存,开销大。
  2. 存于单台服务器上,分布式应用上扩展性差。就是session在一台服务器上,其他服务器不知道此session的存在。
  3. 不安全。容易受到SCRF(Cross-site request forgery)跨站请求伪造攻击。

因此有了基于token的身份验证方式

基于token的身份验证

服务器不必在服务器中存用户的验证数据。
具体步骤:

  1. 客户端在请求体中携带用户名和密码,即username和password,发送请求给服务器端。
  2. 服务器端根据username到数据库查询password,查询验证成功,服务端会签发一个 token,再把这个 token 发送给客户端
  3. 客户端收到 token 以后可以把它存储起来,比如放在 cookie 里或者 Local Storage 里。以后每次客户端访问服务器都要携带此token
  4. 服务器接收到携带token的请求后,验证是否正确。

问题:token如何签发,如何验证?

  • JWT是什么?
    用Json web token (JWT)为例进行说明。
    Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

  • JWT长什么样?
    JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。长这样
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

  • JWT的构成
    第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
    header
    jwt的头部承载两部分信息:

    • 声明类型,这里是jwt
    • 声明加密的算法 通常直接使用 HMAC SHA256

    完整的头部就像下面这样的JSON:

{
  'typ': 'JWT',
  'alg': 'HS256'
}

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

playload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

  • 标准中注册的声明

  • 公共的声明

  • 私有的声明
    标准中注册的声明 (建议但不强制使用) :

  • iss: jwt签发者

  • sub: jwt所面向的用户

  • aud: 接收jwt的一方

  • exp: jwt的过期时间,这个过期时间必须要大于签发时间

  • nbf: 定义在什么时间之前,该jwt都是不可用的.

  • iat: jwt的签发时间

  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
    公共的声明 :
    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

定义一个payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

然后将其进行base64加密,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
优点

  • 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
  • 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
  • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
  • 它不需要在服务端保存会话信息, 所以它易于应用的扩展

转载:https://www.jianshu.com/p/576dbf44b2ae
转载: https://www.cnblogs.com/ella-li/p/12008069.html

posted @ 2022-04-02 23:28  我在我在  阅读(76)  评论(0)    收藏  举报