文章脉络
Cookie和Session
Http是一种无状态协议,即每次得到一次请求都是一个全新的请求,服务端并不知道客户端的历史请求记录;Session和Cookie机制就是为了弥补Http无法辨识用户这一痛点所产生的技术。
什么是Session?
服务器接收到一个请求时,会在内存区域开辟一块空间并生成SessionId号,这个ID是由服务器生成和维护的。
Session机制是如何判断是否为同一会话的?
- 客户端A给服务端B发送一个请求(Http Request)
- 服务端接收到了请求并会生成一个唯一标识(SessionId)
- 在给客户端的响应头(Response Headers)中加入Set-Cookie:SessionName=SessionId要求客户端设置Cookie。不同的服务器对SessionName叫法不同,比如PHP的是PHPSESSIONID,Tomcat是JESSIONID;SessionID采用哈希算法随机生成。
- 客户端接收到响应后,会在本地设置一个SessionName=SessionId的Cookie信息,接下来每次请求都会携带该Cookie信息;该Cookie生命的结束就是会话的结束。
Session的缺点
当一个项目集群部署时,Session无法共享,对于服务器来说Session的作用域是一个主机。
什么是Cookie?
Session是由服务端维护的,Cookie是由客户端管理。
由于Http是无状态的,所以服务端想知道用户做了写什么,需要通过特殊的手段,Session的目的是为了标识"访问者的身份",Cookie算是Session机制下的"协调者"。
服务器命令浏览器设置的Cookie,浏览器会进行存储,并与下一个请求合并一起提交到服务器,
Cookie的创建
服务器可以在给客户端的响应头(Response Header)设置一个或多个Set-Cookie参数,客户端(通常是浏览器)会存储为Cookie。
Cookie分类
Cookie总是保存在客户端中,按在客户端中的存储位置可以分为内存Cookie(会话Cookie)和磁盘Cookie(永久|时效)性Cookie。
内存由浏览器维护,保护在浏览器进程中,进程关掉了,Cookie也就消失了;硬盘Cookie保存在硬盘中会设置一个过期时间,除非时间到期或者手工清除,Cookie就不会被清除。
会话Cookie
当Set-Cookie
中没有指定Expires
或Max-Age
属性时,就是一个会话Cookie。会话Cookie是由客户端进程维护的,存储于内存中,客户端关闭后Cookie也就消失。但客户端也可以将内存中的Cookie持久化到磁盘中。
永久(时效)性Cookie
永久性Cookie不会在Expries
指定的时间或Max-Age
特定时间长度内过期
Cookie的作用域
Domain
和Path
标识定义了Cookie的作用域;即Cookie应该发送哪些URL。
Domain
指定了哪些主机可以接受Cookie,如果不指定默认为当前主机(不包含子域名)。如果指定了Domain
,则一般包含子域名。
例如如果设置Domain=mozilla.org
,则Cookie也会包含在它的子域名中(如developer.mozila.org
)。
如果设置Path=/docs
,则会匹配形如mozilla.org/docs**
的子域名。
JWT和Session Cookies
JWT和Session Cookie都可以为网站提供身份认证
什么是Session Cookies?
Session Cookie 也就是会话Cookie
,上面提到了,客户端访问服务端后,服务端计算一个SessionId然后放到响应头的Set-Cookie属性中,这个让客户端设置的SessionId只是用于标识会话
,而Cookie的作用不止是标识会话。
什么是JWT(Json Web Token)?
全称为Json Web Token
,通常可以称为Json 令牌
。它是RFC 7519
中定义的用于安全的
将信息作为Json
对象传输的一种形式。
JWT中存储的信息是通过数字校验的
,因此是安全的。
可以使用HMAC算法或RSA/ECDSA的公用/专用秘钥对JWT进行签名。
使用JWT主要有以下两点:
认证(Authorization)
:这是使用JWT最常用的一种情况,一旦用户登录,后面的每个请求都会携带JWT,从而允许用户访问该令牌所允许的路由、服务和资源。单点登录(SSO)
是当今广泛使用JWT的一项功能,因为它的开销很小。信息交换(Information Exchange)
:JWT是能安全传输信息的一种方式,通过公钥/私钥对JWT进行签名认证。此外,由于签名是使用head
和payload
计算的,因此还可以验证内容是否被篡改。
JWT的格式
JWT由三部分组成,每个部分用.
分割,三个部分分别是:
- Header(头部)
- Payload(负载)
- Signature(签名)
Header
Header是JWT的标头,通常指定令牌的类型
和签名算法
,例如:
{
"alg" : "HS256",
"typ" : "JWT"
}
alg
表示签名的算法(algorithm),默认是HMAC-SHA256(HS256),typ
表示这个令牌的类型(type)。
最后会用Base64编码
将上述JSON转移成字符串。
Payload
Payload也是一组字段,JWT规定了7个官方字段供选用:
字段名 | 字段说明 |
---|---|
iss(issuer) | 签发人 |
exp(expiration time) | 过期时间 |
sub(subject) | 主题 |
aud(audience) | 受众 |
nbf(not before) | 生效时间 |
iat(issued at) | 签发时间 |
jti(jwt id) | 编号 |
例如:
{
"sub" : "123456",
"name" : "zhangsan",
"admin" : true
}
JWT默认不加密,所以重要信息尽量不要放这里。
最后会用Base64编码
将上述JSON转移成字符串。
Signature
Signature是对前两个部分进行签名,以防止被中间人篡改。
首先需要制定一个秘钥(secret),这个秘钥只有服务器才知道。然后使用Header里指定的签名算法按照公式产生签名,假设为默认的HMAC-SHA256,公式如下:
HMAC-SHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);
算出签名后把Header、Payload、Signature三个部分拼接成字符串。可以在HTTP环境中轻松传递这些字符串。
JWT和Session Cookies的相似之处
都可以进行身份验证,都可以维持会话状态
JWT和Session Cookies的异同之处
- JWT有签名,Session没有
- JWT是无状态的,签发后在到期之前都会有效,而不是由某个服务器来维持
- 大量用户下,Session的维持需要占据大量内存,JWT可以节省空间开销
- JWT可以用来跨域访问,Session Cookie只能作用域单个节点的域或者它的子域;JWT可以通过多个节点进行用户认证,也就是跨域认证
JWT和Session Cookies的选型
对于只需要登录用户并访问存储在站点数据库中的一些信息的中小型站点来说Session Cookie就能满足;
如果节点很多而且需要处理大量请求,那么内存开销是个问题,使用JWT或许更合适
后记
用户禁止Cookie后,服务器的SessionId还会发给用户么?
会的,只是浏览器无法存储这个sessionid到cookie域中。
用户禁止Cookie后,如何继续使用Cookie?
Session需要Cookie来维持,对于网站来说,禁用Cookie并不等于真的禁用Cookie,只是Cookie失去了在客户端上"持久化"的作用而已。这种情况下可以在URL上带上SESSIONID=xxxx,按Restful中的get方式去请求。也就是重写URL的方式。
还有另外一种说法,Session的实现方式有两种,一种是Cookie,一种是Url重写。
- 浏览器支持Cookie时,创建SessionId后会把SessionId存储在客户端中;
- 如果浏览器不支持Cookie,那么就会使用Url重写的方式,让服务端生成这个地址,这个地址会带上SessionId=xxxx,之后用户通过点击这个地址访问服务器时会带上SessionId,这样也维持了会话
bug
文章可能有些逻辑不严密的地方,之后会慢慢查找文献修补过来,希望看官海涵,比心( ̄▽ ̄)~*。