Cookie、Session、Token、JWT
Cookie、Session、Token、JWT
引入这些技术主要是为了保持状态。HTTP协议是无状态协议。
Cookie
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
用于关联 Cookie
和 Session
Cookie和Session验证用户的流程
用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的
Session
请求返回时将此
Session
的唯一标识信息SessionID
返回给浏览器浏览器接收到服务器返回的
SessionID
信息后,会将此信息存入到Cookie
中,同时 Cookie 记录此SessionID
属于哪个域名当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在
Cookie
信息,如果存在自动将Cookie
信息也发送给服务端,服务端会从Cookie
中获取SessionID
,再根据SessionID
查找对应的Session
信息,如果没有找到说明用户没有登录或者登录失效,如果找到Session
证明用户已经登录可执行后面操作。
Token
访问资源接口(API
)时所需要的资源凭证。
基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
token 完全由应用管理,所以它可以避开同源策略
Access Token
用于每次请求校验
简单Token的组成:
uid
(用户唯一的身份标识)、time
(当前时间的时间戳)、sign
(签名,token
的前几位以哈希算法压缩成的一定长度的十六进制字符串)
特点:
服务端无状态化、可扩展性好、支持移动端设备、支持跨程序调用
Access Token 验证用户的流程
客户端使用用户名跟密码请求登录,服务器端收到请求,去验证用户名与密码
验证成功后,服务器端会签发一个
token
并把这个token
发送给客户端客户端收到
token
以后,会把它存储起来,比如放在localStorage
或者sessionStorage
里客户端每次向服务端请求资源的时候需要在
Header
中携带着服务端签发的token
服务端收到请求,然后去验证客户端请求里面带着的
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个月的
refresh token
和有效期为1天的access token
- 客户端收到两个
token
后,存储起来,客户端每次请求数据时,使用access token
-
access token
失效后,服务器端返回错误,客户端使用refresh token
向服务器端发送请求刷新access token
- 服务器端需要判断
refresh token
是否过期,如果refresh token
有效,则服务器端返回新签发的access token
,如果refresh token
过期,则服务器端返回错误,客户端需要用户重新登录
Session 和 Token 的区别
Session
是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token
是令牌,访问资源接口时所需要的资源凭证。Token
使服务端无状态化,不会存储会话信息。
Session
和 Token
并不矛盾,作为身份认证 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)。
是一种认证授权机制。
JWT
是 Token
的一种实现形式。将 Token
和 Payload
(负载,包括签发人等信息) 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT
自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT
自包含了用户信息和加密的数据。
JWT
的原理是,服务器认证以后,生成一个 JSON
对象并携带签名,发回给用户。
JWT
的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。
可以使用 HMAC
算法或者是 RSA
的公/私秘钥对 JWT
进行签名。因为数字签名的存在,这些传递的信息是可信的。
因为用户的状态不再存储在服务端的内存中,所以这是一种无状态的认证机制
使用过程中无法废弃某个 Token 或者更改 Token 的权限。也就是说一旦 JWT 签发了,到期之前就会始终有效,除非服务器部署额外的逻辑。
JWT 认证流程
- 用户输入用户名/密码登录,服务端认证成功后,使用密钥创建
JWT
后并返回给客户端 - 客户端将
JWT
保存到本地 - 当用户希望访问一个受保护的路由或者资源的时候,需要请求头的
Authorization
字段中使用Bearer
模式添加JWT
- 服务端的保护路由将会检查请求头
Authorization
中的JWT
信息,如果合法,则允许用户的行为