Cookie、Session、Token、JWT

Cookie、Session、Token、JWT

引入这些技术主要是为了保持状态。HTTP协议是无状态协议。

cookie存储在客户端

cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。浏览器可储存cookie总大小为4095~4097个字节(不同浏览器不同)。

cookie是不可跨域的

每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain, 如: www.baidu.com)。

限制Cookie访问
Secure属性

标记为 Secure 的 Cookie 只应通过被 HTTPS 协议加密过的请求发送给服务端,因此可以预防 man-in-the-middle 攻击者的攻击。但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确实的安全保障, 例如,可以访问客户端硬盘的人可以读取它。

HttpOnly属性

JavaScript Document.cookie API 无法访问带有 HttpOnly 属性的cookie;此类 Cookie 仅作用于服务器。例如,持久化服务器端会话的 Cookie 不需要对 JavaScript 可用,而应具有 HttpOnly 属性。此预防措施有助于缓解跨站点脚本(XSS)攻击。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

Session

session存储在服务器端

session 是基于 cookie 实现的,session 存储在服务器端,sessionId 会被存储到客户端的cookie中。

sessionId 用于关联 CookieSession

Cookie和Session验证用户的流程

  1. 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session

  2. 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器

  3. 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名

  4. 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。

Token

访问资源接口(API)时所需要的资源凭证。

基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库

token 完全由应用管理,所以它可以避开同源策略

Access Token

用于每次请求校验

简单Token的组成:

uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)

特点:

服务端无状态化、可扩展性好、支持移动端设备、支持跨程序调用

Access Token 验证用户的流程
  1. 客户端使用用户名跟密码请求登录,服务器端收到请求,去验证用户名与密码

  2. 验证成功后,服务器端会签发一个 token 并把这个 token 发送给客户端

  3. 客户端收到 token 以后,会把它存储起来,比如放在 localStorage或者sessionStorage

  4. 客户端每次向服务端请求资源的时候需要在Header中携带着服务端签发的 token

  5. 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据

Refresh Token

refresh token 是专用于刷新 access token

refresh token 有效期要比 access token

access token 过期失效后,每次刷新 access token 都需要用户输入登录用户名与密码,

使用 refresh token,客户端可以直接用 refresh token 去更新 access token,无需用户进行额外的操作。(实现无感知刷新)

Refresh Token 及过期时间是存储在服务器的数据库中,只有在申请新的 Acesss Token 时才会验证,不会对业务接口响应时间造成影响,也不需要向 Session 一样一直保持在内存中以应对大量的请求。

Refresh Token 刷新 Access Token 的流程
  1. 客户端使用用户名跟密码请求登录,服务器端收到请求,去验证用户名与密码
  2. 验证成功后,服务器端签发并返回给客户端有效期为1个月的 refresh token 和有效期为1天的 access token
  3. 客户端收到两个 token 后,存储起来,客户端每次请求数据时,使用 access token
  4. access token 失效后,服务器端返回错误,客户端使用 refresh token 向服务器端发送请求刷新 access token
  5. 服务器端需要判断 refresh token 是否过期,如果 refresh token 有效,则服务器端返回新签发的 access token,如果 refresh token 过期,则服务器端返回错误,客户端需要用户重新登录

Session 和 Token 的区别

Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是令牌,访问资源接口时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。

SessionToken 并不矛盾,作为身份认证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重放攻击,而 Session 就必须依赖链路层来保障通讯安全了。如果你需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态。

Session 只提供一种简单的认证,即只要有此 SessionID ,即认为有此 User 的全部权限。需要严格保密,这个数据应该只保存在站方,不应该共享给其它网站或者第三方 App。如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,则应使用 Token

session 模式扩展性不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

token 可以避免 CSRF 攻击(因为不需要cookie 了)

JWT ( JSON Web Token )

目前最流行的跨域认证解决方案。JWT在线网站 https://jwt.io/

JWT 是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准(RFC 7519)。

是一种认证授权机制

JWTToken 的一种实现形式。将 TokenPayload(负载,包括签发人等信息) 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。

JWT原理是,服务器认证以后,生成一个 JSON 对象并携带签名,发回给用户。

JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。

可以使用 HMAC 算法或者是 RSA 的公/私秘钥对 JWT 进行签名。因为数字签名的存在,这些传递的信息是可信的。

因为用户的状态不再存储在服务端的内存中,所以这是一种无状态的认证机制

使用过程中无法废弃某个 Token 或者更改 Token 的权限。也就是说一旦 JWT 签发了,到期之前就会始终有效,除非服务器部署额外的逻辑。

JWT 认证流程
  1. 用户输入用户名/密码登录,服务端认证成功后,使用密钥创建 JWT 后并返回给客户端
  2. 客户端将 JWT 保存到本地
  3. 当用户希望访问一个受保护的路由或者资源的时候,需要请求头的 Authorization 字段中使用Bearer 模式添加 JWT
  4. 服务端的保护路由将会检查请求头 Authorization 中的 JWT 信息,如果合法,则允许用户的行为

参考链接

JSON Web Token 入门教程