一 基本知识
为什么需要会话管理
HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息)。每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态需要通过 cookie 或者 session 去实现。
定义:
cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。
Session 代表着服务器和客户端一次会话的过程。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在访问不同web页面的时候,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当客户端关闭会话,或者 Session 超时失效时会话结束。
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
二 流程
cookie和session流程
- 用户登录,输入账号密码;
- 服务器验证账号密码是否正确,并创建会话,然后把会话数据存储在数据库中;并将seesion ID(加密过的)保存在cookie中返回到浏览器
- 具有seesion ID的cookie保存在用户浏览器
- 接下来请求中,浏览器携带cookie一并发给服务器,服务器会根据数据库验证session ID,如果验证通过,则继续处理;
- 一旦用户登出,服务端和客户端同时销毁该会话。
token和session流程
用户输入登录信息
服务器判断登录信息正确,返回一个 token(一般是JWT)
token 存储在客户端,保存在 local storage(一般保存这里), session storage 或者 cookie 。
接着发起请求的时候将 token 放进url参数或者http header ( Authorization header)
服务器端用私钥对数据进行加密得到的签名, 跟token里面的签名进行比较,如果签名一样且时间有效,则处理该请求。
一旦用户登出,token 在客户端被销毁,没有服务端。
三 token
为什么要token?
每个用户只需要保存自己的会话标识(Session ID),而服务端则要保存所有用户的Session ID。 如果访问服务端的用户逐渐变多, 就需要保存成千上万,而且服务端是由多台服务器组成的一个集群, 用户通过服务器A登录了系统, 那session id会保存在服务器A上, 假设用户下一次请求被转发到服务器B, 服务器B可没有用户的 session id。
怎么判断token是否是伪造?
服务端对数据做一个签名(Sign), 比如说服务端用 HMAC-SHA256 加密算法,再加上一个只有服务端才知道的密钥, 对数据做一个签名, 把这个签名和数据一起作为 Token 发给客户端, 客户端收到 Token 以后可以把它存储起来,比如存储在 Cookie 里或者 Local Storage 中,由于密钥除了服务端任何其他用户都不知道, 就无法伪造令牌(Token)。
当用户把这个Token发给服务端时,服务端使用相同的HMAC-SHA256 算法和相同的密钥,对数据再计算一次签名, 和 Token 中的签名做个对比, 如果相同,说明用户已经登录过了, 即验证成功。若不相同, 那么说明这个请求是伪造的。
存储地方:
上面我们说了token可以存储在Cookie 里或者 Local Storage 中,那存储在不同地方有什么危害呢
Web存储(local Storage/sessionStorage)可以通过同一域Javascript访问。这意味着任何在你的网站上的运行的JavaScript都可以访问Web存储,所以容易受到XSS攻击。
另一方面,如果你用 cookie 来存储 JWT,你可以制定httponly,来防止被JavaScript读取,也可以制定secure,来保证token只在HTTPS下传输。但是需要防护 CSRF攻击。
还是建议存储在local Storage,XSS我们可以设置检查函数过滤传进来的参数,而且cookie大小有限,并不能储存太大的token。
有效的保护方法:
给 token 设置一个短期过期时间,即使 token 被其他人获取,也会很快不能再用。此外,还可以创建一个受攻击的 token 黑名单,不允许这些黑名单的 token 访问系统。
四 区别
cookie跟session区别
- 作用范围不同,Cookie 保存在客户端,Session 保存在服务器端。
- 存取方式的不同,Cookie 只能保存 ASCII,Session 可以存任意数据类型。
- 有效期不同,Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭或者 Session 超时都会失效。
- 隐私策略不同,Cookie 存储在客户端,比较容易遭到不法获取,Session 存储在服务端,安全性相对 Cookie 要好一些。
- 存储大小不同, 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie。
token(存储在Local Storage中)跟cookie区别:
- token无状态的,后端服务不需要记录token。
- token 的 CORS 可以很好的处理跨域的问题。由于每次发送请求到后端,都需要检查 JWT,只要它们被验证通过就可以处理请求。cookie只能单域或者子域
- token支持移动平台,cookie不支持
- 可防跨站请求(CSRF),因为token黑客难构造也无法通过CSRF获取
五 JWT
定义
JSON Web Token (JWT)是一个开放标准(RFC 7519),它用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的,本质上也是token。
使用场景
- Authorization (授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
- Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWT可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。
JWT构成
JWT是由三段信息构成的,用.将三段信息连成一个JWT字符串,类似于aa.bb.cc。
头部(header).消息体(payload).签证(signature)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
注意:header和payload不要写入敏感信息
header
header主要有2个部分:
- 声明类型,这里是jwt
- 声明加密的算法 (HMAC SHA256和RSA等),通常直接使用 HMAC SHA256
就像下面的json
{
'typ': 'JWT',
'alg': 'HS256'
}
之后用Base64对这个json编码就得到第一段信息
payload
消息体就是存放有效信息的地方,它包含声明(要求),声明是关于实体(通常是用户)和其他数据的声明,声明有三种类型。
- 标准中注册的声明
- 公共的声明
- 私有的声明
标准中注册的声明(推荐使用,不强制)
- iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息,自定义私有的声明 :
私有声明用于同意使用它们的各方之间共享信息,并且不是注册的或公开的声明
例子:{ "sub": '123426711', "name": 'assion', "admin":true }
之后base64加密
Signature
这个签证信息由三部分组成:header (base64后的)、 payload (base64后的) 、secret(盐=私钥)
这个部分需要header (base64后的)和payload (base64)后的使用.连接组成的字符串,然后通过header中声明的加密方式进行加secret盐组合加密,然后就构成了jwt的第三部分。
// javascript var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, 'secret');
//TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
注意:secret(私钥)是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,不能泄露出去
流程:
优点:
- 因为json的通用性,所以JWT可以进行跨语言支持的,像JAVA,JavaScript,PHP等很多语言都可以使用。
- JWT可以在payload部分存储一些其他业务逻辑所必要的非敏感信息。
- jwt的构成简单,字节占用小,便于传输,
- 不需要在服务端保存会话信息, 易于应用的扩展