彻底搞懂Token、Session和Cookie
HTTP 是⽆状态的,全部的请求都是⽆状态的。然⽽,某些情况下我们想让我们的状态能被记住。⽐如,浏览⼀家在线商店,当我们把⾹蕉放到购物车中后,再去其他页⾯购买苹果时,并不希望我们的⾹蕉消失。在在线商店的各个页⾯中穿梭时,我们是希望想我们的购买状态是能够被记住的!
为了克服 HTTP 请求⽆状态的性质,我们可以使⽤ session 或者 token。简单来说有两种⽅式可以记住⽤户的状态
session和token都是⽤来保持会话,功能相同。
基于 Session
基于 session 的认证中,⽤户登录后服务器会为登录⽤户创建⼀个 session,Cookie的验证是有状态的,sessionid 会保存在⽤户浏览器的 cookie 中。当⽤户登录成功
后,cookie 会随着后边的每个请求⼀起发送。这样,服务器通过 cookie 中的 sessionid 到内存中的 session 数据,来验证⽤户⾝份,从⽽在响应中返回相应的状态。
1.客户端发送⼀个http请求带着⽤户名密码到服务器端
2.服务器端接受了客户端请求后,建⽴⼀个session,并发送⼀个http响应到客户端,这个响应头包括了set-cookie的头部,头部⾥⾯包括了sessionid
set-cookie的格式如下 Set-Cookie:value [ ;expire=date ][ ;damain=domain ][ ;path=path ][ ;secure ]
3.客户端发起第⼆次请求,服务器已经给了setcookie,浏览器⾃动在请求头上获取到cookie并分解验证信息成功后返回respense给客户端
session的弊端:
session是服务端存储的⼀个对象,主要⽤来存储所有访问过该服务端的客户端的⽤户信息(也可以存储其他信息),从⽽实现保持⽤户会话状态。但是服务器重启时,内存会被销毁,存储的⽤户信息也就消失了。
    不同的⽤户访问服务端的时候会在session对象中存储键值对,“键”⽤来存储开启这个⽤户信息的“钥匙”,在登录成功后,“钥匙”通过cookie返回给客户端,客户端存储为sessionId记录在cookie中。当客户端再次访问时,会默认携带cookie中的sessionId来实现会话机制。
session是基于cookie的。
1. cookie的数据4k左右
2. cookie存储数据的格式:字符串key=value
3. cookie存储有效期:可以⾃⾏通过expires进⾏具体的⽇期设置,如果没设置,默认是关闭浏览器时失效。
4. cookie有效范围:当前域名下有效。所以session这种会话存储⽅式⽅式只适⽤于客户端代码和服务端代码运⾏在同⼀台服务器上(前后端项⽬协议、域名、端⼝号都⼀
致,即在⼀个项⽬下)
session持久化
    ⽤于解决重启服务器后session就消失的问题。在数据库中存储session,⽽不是存储在内存中。通过包:express-mysql-session
其它
    当客户端存储的cookie失效后,服务端的session不会⽴即销毁,会有⼀个延时,服务端会定期清理⽆效session,不会造成⽆效数据占⽤存储空间的问题。
基于 Token
很多⽹络应⽤使⽤ json web token 也即 JWT 来代替 session 实现⾝份认证。在这种基于 token 的应⽤中,服务器使⽤⼀个密钥来创建 jwt 并发送给客户端。客户端会保存此
jwt(通常保存在本地存储 local storage 中)并在每个请求的 header 中包含此 jwt。服务器验证客户端发来的每个请求中的 jwt ,做出响应。 token 的验证是⽆状态的,存储在Authorization Header 中进⾏验证,形式是Bear{ JWT }
它与 session ⽅式最⼤的不同是⽤户状态不存储在服务器端,⽽是存储在 token 中并保存在客户端。为了扩展性,⼤部分现代⽹络应⽤都使⽤ jwt 来进⾏⽤户认证。
token的组成⼀般是  uid(⽤户唯⼀⾝份标识)+time(时间戳)+sign(签名使⽤hash压缩成固长的⼗六进制字符串防⽌第三⽅恶意拼接)+固定参数可选
1.⽤户登录,成功后服务器返回Token给客户端
2.客户端收到数据后保存在客户端
3.客户端再次访问服务器,将token放header中
4.服务器采⽤filter进⾏过滤校验,成功返回请求数据,校验失败返回错误码
适⽤于项⽬级的前后端分离(前后端代码运⾏在不同的服务器下)
    请求登录时,token和sessionId原理相同,是对key和key对应的⽤户信息进⾏加密后的加密字符,登录成功后,会在响应主体中将{token:'字符串'}返回给客户端。客户端通过cookie、sessionStorage、localStorage都可以进⾏存储。再次请求时不会默认携带,需要在请求位置给请求头中添加认证字段Authorization携带token信息,服务器端就可以通过token信息查⽤户登录状态。
扩展性
基于 session: 由于 session 存储于服务器端(⼀般是内存型数据库,如 redis),当⽤户量很⼤时会有⼀定的扩展性问题。
基于 token: 存储在客户端,不存在上边这个问题。
token可以抵抗csrf(跨域请求伪造),更安全,使⽤cookie在post请求的同时会⾃动添加到请求头上,token则不会⾃动添加到请求头中,
攻击者也⽆法访问⽤户的token,⽆法形成攻击。
多设备
基于 session: cookie 通常⼯作在单个域名或其⼦域名下,⽽且跨域名时通常会被浏览器关闭。当 API 要服务于不同域名的移动和⽹络设备时,容易出现问题。
基于 token: 由于 jwt 包含于请求头当中,不存在 cookie 引发的相关的问题。
翻译⾃:
关于 jwt 的更多信息,可以参考阮⼀峰的⽂章
***********************************************************************************************************************************************************************
很久很久以前,Web 基本上就是⽂档的浏览⽽已,既然是浏览,作为服务器,不需要记录谁在某⼀段时间⾥都浏览了什么⽂档。
发展史
1、很久很久以前,Web 基本上就是⽂档的浏览⽽已,既然是浏览,作为服务器,不需要记录谁在某⼀段时间⾥都浏览了什么⽂档。
每次请求都是⼀个新的HTTP协议,就是请求加响应,尤其是我不⽤记住是谁刚刚发了HTTP请求,每个请求对我来说都是全新的。这段时间很嗨⽪。
2、但是随着交互式Web应⽤的兴起,像在线购物⽹站,需要登录的⽹站等等,马上就⾯临⼀个问题,那就是要管理会话,必须记住哪些⼈登录系统,哪些⼈往⾃⼰的购物车中放商品。
也就是说我必须把每个⼈区分开,这就是⼀个不⼩的挑战,因为HTTP请求是⽆状态的,所以想出的办法就是给⼤家发⼀个会话标识(session id)。
说⽩了就是⼀个随机的字串,每个⼈收到的都不⼀样,每次⼤家向我发起HTTP请求的时候,把这个字符串给⼀并捎过来,这样我就能区分开谁是谁了。
3、这样⼤家很嗨⽪了,可是服务器就不嗨⽪了,每个⼈只需要保存⾃⼰的session id,⽽服务器要保存所有⼈的session id 。如果访问服务器多了,就得由成千上万,甚⾄⼏⼗万个。
这对服务器来说是⼀个巨⼤的开销,严重的限制了服务器扩展能⼒。
⽐如说我⽤两个机器组成了⼀个集,⼩F通过机器A登录了系统,那session id会保存在机器A上,假设⼩F的下⼀次请求被转发到机器B怎么办?机器B可没有⼩F的 session id 啊。
有时候会采⽤⼀点⼩伎俩:session sticky ,就是让⼩F的请求⼀直粘连在机器A上,但是这也不管⽤,要是机器A挂掉了,还得转到机器B去。
那只好做session 的复制了,把session id 在两个机器之间搬来搬去,快累死了。
后来有个叫Memcached的⽀了招:把session id 集中存储到⼀个地⽅,所有的机器都来访问这个地⽅的数据。
这样⼀来,就不⽤复制了,但是增加了单点失败的可能性,要是那个负责session 的机器挂了,所有⼈都得重新登录⼀遍,估计得被⼈骂死。
也尝试把这个单点的机器也搞出集,增加可靠性,但不管如何,这⼩⼩的session 对我来说是⼀个沉重的负担。 4、于是有⼈就⼀直在思考,我为什么要保存这可恶的session
呢,只让每个客户端去保存该多好? 可是如果不保存这些session id ,怎么验证客户端发给我的session id 的确是我⽣成的呢?
如果不去验证,我们都不知道他们是不是合法登录的⽤户,那些不怀好意的家伙们就可以伪造session id,为所欲为了。嗯,对了,关键点就是验证 ! ⽐如说,⼩F已经登录了系统,我给他发⼀个令牌(token),⾥边包含了⼩F的 user id,下⼀次⼩F 再次通过Http 请求访问我的时候,把这个token 通过Http header 带过来不就可以了。不过这和session id 没有本质区别啊,任何⼈都可以可以伪造,所以我得想点⼉办法,让别⼈伪造不了。
那就对数据做⼀个签名吧,⽐如说我⽤HMAC-SHA256 算法,加上⼀个只有我才知道的密钥,对数据做⼀个签名,把这个签名和数据⼀起作为token,由于密钥别⼈不知道,就⽆法伪造token了。
这个token 我不保存,当⼩F把这个token 给我发过来的时候,我再⽤同样的HMAC-SHA256 算法和同样的密钥,对数据再计算⼀次签名,和token 中的签名做个⽐较,如果相同,我就知道⼩F已经登录过了,并且可以直接取到⼩F的user id,如果不相同,数据部分肯定被⼈篡改过,我就告诉发送者:对不起,没有认证。
Token 中的数据是明⽂保存的(虽然我会⽤Base64做下编码,但那不是加密),还是可以被别⼈看到的,所以我不能在其中保存像密码这样的敏感信息。
当然,如果⼀个⼈的token 被别⼈偷⾛了,那我也没办法,我也会认为⼩偷就是合法⽤户,这其实和⼀个⼈的session id 被别⼈偷⾛是⼀样的。这样⼀来,我就不保存session id 了,我只是⽣成token ,然后验证token ,我⽤我的CPU计算时间获取了我的session 存储空间 ! 解除了session id这个负担,可以说是⽆事⼀⾝轻,我的机器集现在可以轻松地做⽔平扩展,⽤户访问量增⼤,直接加机器就⾏。这种⽆状态的感觉实在是太好了!
Cookie
cookie 是⼀个⾮常具体的东西,指的就是浏览器⾥⾯能永久存储的⼀种数据,仅仅是浏览器实现的⼀种数据存储功能。
cookie由服务器⽣成,发送给浏览器,浏览器把cookie以kv形式保存到某个⽬录下的⽂本⽂件内,下⼀次请求同⼀⽹站时会把该cookie发送给服务器。
由于cookie是存在客户端上的,所以浏览器加⼊了⼀些限制确保cookie不会被恶意使⽤,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。
Session
session 从字⾯上讲,就是会话。这个就类似于你和⼀个⼈交谈,你怎么知道当前和你交谈的是张三⽽不是李四呢?对⽅肯定有某种特征(长相等)表明他就是张三。
session 也是类似的道理,服务器要知道当前发请求给⾃⼰的是谁。
为了做这种区分,服务器就要给每个客户端分配不同的“⾝份标识”,然后客户端每次向服务器发请求的时候,都带上这个“⾝份标识”,服务器就知道这个请求来⾃于谁了。
⾄于客户端怎么保存这个“⾝份标识”,可以有很多种⽅式,对于浏览器客户端,⼤家都默认采⽤ cookie 的⽅式。
服务器使⽤session把⽤户的信息临时保存在了服务器上,⽤户离开⽹站后session会被销毁。
这种⽤户信息存储⽅式相对cookie来说更安全,可是session有⼀个缺陷:如果web服务器做了负载均衡,那么下⼀个操作请求到了另⼀台服务器的时候session会丢失。
Token
在Web领域基于Token的⾝份验证随处可见。在⼤多数使⽤Web API的互联⽹公司中,tokens 是多⽤户下处理认证的最佳⽅式。
以下⼏点特性会让你在程序中使⽤基于Token的⾝份验证:
1. ⽆状态、可扩展
2. ⽀持移动设备
3. 跨程序调⽤
4. 安全
那些使⽤基于Token的⾝份验证的⼤佬们
⼤部分你见到过的API和Web应⽤都使⽤tokens。例如Facebook, Twitter, Google+, GitHub等。
Token的起源
在介绍基于Token的⾝份验证的原理与优势之前,不妨先看看之前的认证都是怎么做的。
基于服务器的验证
我们都是知道HTTP协议是⽆状态的,这种⽆状态意味着程序需要验证每⼀次请求,从⽽辨别客户端的⾝份。
在这之前,程序都是通过在服务端存储的登录信息来辨别请求的。这种⽅式⼀般都是通过存储Session来完成。随着Web,应⽤程序,已经移动端的兴起,这种验证的⽅式逐渐暴露出了问题。尤其是在可扩展性⽅⾯。
基于服务器验证⽅式暴露的⼀些问题
1. Seesion:每次认证⽤户发起请求时,服务器需要去创建⼀个记录来存储信息。当越来越多的⽤户发请求时,内存的开销也会不断增加。
2. 可扩展性:在服务端的内存中使⽤Seesion存储登录信息,伴随⽽来的是可扩展性问题。签名字符串是什么
3. CORS(跨域资源共享):当我们需要让数据跨多台移动设备上使⽤时,跨域资源的共享会是⼀个让⼈头疼的问题。在使⽤Ajax抓取另⼀个域的资源,就可以会出现禁⽌请求的情况。
4. CSRF(跨站请求伪造):⽤户在访问银⾏⽹站时,他们很容易受到跨站请求伪造的攻击,并且能够被利⽤其访问其他的⽹站。
在这些问题中,可扩展⾏是最突出的。因此我们有必要去寻求⼀种更有⾏之有效的⽅法。
基于Token的验证原理
基于Token的⾝份验证是⽆状态的,我们不将⽤户信息存在服务器或Session中。
这种概念解决了在服务端存储信息时的许多问题。
NoSession意味着你的程序可以根据需要去增减机器,⽽不⽤去担⼼⽤户是否登录。
基于Token的⾝份验证的过程如下:
1. ⽤户通过⽤户名和密码发送请求。
2. 程序验证。
3. 程序返回⼀个签名的token 给客户端。
4. 客户端储存token,并且每次⽤于每次发送请求。
5. 服务端验证token并返回数据。
每⼀次请求都需要token。token应该在HTTP的头部发送从⽽保证了Http请求⽆状态。
我们同样通过设置服务器属性Access-Control-Allow-Origin:* ,让服务器能接受到来⾃所有域的请求。
需要注意的是,在ACAO头部标明(designating)*时,不得带有像HTTP认证,客户端SSL证书和cookies的证书。
实现思路:
1. ⽤户登录校验,校验成功后就返回Token给客户端。
2. 客户端收到数据后保存在客户端
3. 客户端每次访问API是携带Token到服务器端。
4. 服务器端采⽤filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码。当我们在程序中认证了信息并取得token之后,我们便能通过这个Token做许多的事情。我们甚⾄能基于创建⼀个基于权限的token传给第三⽅应⽤程序,这些第三⽅程序能够获取到我们的数据(当然只有在我们允许的特定的token)。
Tokens的优势
⽆状态、可扩展
在客户端存储的Tokens是⽆状态的,并且能够被扩展。基于这种⽆状态和不存储Session信息,负载负载均衡器能够将⽤户信息从⼀个服务传到其他服务器上。
如果我们将已验证的⽤户的信息保存在Session中,则每次请求都需要⽤户向已验证的服务器发送验证信息(称为Session亲和性)。⽤户量⼤时,可能会造成⼀些拥堵。
但是不要着急。使⽤tokens之后这些问题都迎刃⽽解,因为tokens⾃⼰hold住了⽤户的验证信息。
安全性
请求中发送token⽽不再是发送cookie能够防⽌CSRF(跨站请求伪造)。
即使在客户端使⽤cookie存储token,cookie也仅仅是⼀个存储机制⽽不是⽤于认证。不将信息存储在Session中,让我们少了对session操作。
token是有时效的,⼀段时间之后⽤户需要重新验证。我们也不⼀定需要等到token⾃动失效,token有撤回的操作,通过token revocataion可以使⼀个特定的token或是⼀组有相同认证的token⽆效。
可扩展性
Tokens能够创建与其它程序共享权限的程序。
例如,能将⼀个随便的社交帐号和⾃⼰的⼤号(Fackbook或是Twitter)联系起来。
当通过服务登录Twitter(我们将这个过程Buffer)时,我们可以将这些Buffer附到Twitter的数据流上(we are allowing Buffer to post to our Twitter stream)。
使⽤tokens时,可以提供可选的权限给第三⽅应⽤程序。当⽤户想让另⼀个应⽤程序访问它们的数据,我们可以通过建⽴⾃⼰的API,得出特殊权限的tokens。
多平台跨域
我们提前先来谈论⼀下CORS(跨域资源共享),对应⽤程序和服务进⾏扩展的时候,需要介⼊各种各种的设备和应⽤程序。
Having our API just serve data, we can also make the design choice to serve assets from a CDN. This eliminates the issues that CORS brings up after we set a quick header configuration for our application.
只要⽤户有⼀个通过了验证的token,数据和资源就能够在任何域上被请求到。
基于标准创建token的时候,你可以设定⼀些选项。我们在后续的⽂章中会进⾏更加详尽的描述,但是标准的⽤法会在JSON Web Tokens体现。
最近的程序和⽂档是供给JSON Web Tokens的。它⽀持众多的语⾔。这意味在未来的使⽤中你可以真正的转换你的认证机制。
参考⽂档
********************************************************************************************
Cookie和Session的区别:
1、cookie数据由服务端⽣成发送存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别⼈可以分析存放在本地的cookie并进⾏cookie欺骗,考虑到安全应当使⽤session。
3、session会在⼀定时间内保存在服务器上。当访问增多,会⽐较占⽤你服务器的性能,考虑到减轻服务器性能⽅⾯,应当使⽤cookie。
4、数据格式是键值对,单个cookie保存的数据不能超过4K,很多浏览器都限制⼀个站点最多保存20个cookie。
5、cookie数据过期机制是设置expire值
6、所以个⼈建议:
将登陆信息等重要信息存放为session
其他信息如果需要保留,可以放在cookie中
cookie有很多使⽤场景,在项⽬中⽐较常见的有:
  1.登录记住⽤户名
  2.记录⽤户浏览记录
Token 和 Session 的区别:
session和 token并不⽭盾,作为⾝份认证token安全性⽐session好,因为每个请求都有签名还能防⽌监听以及重放攻击,⽽session就必须靠链路层来保障通讯安全了。如上所说,如果你需要实现有状态的会话,仍然可以增加session来在服务器端保存⼀些状态
App通常⽤restful api跟server打交道。Rest是stateless的,也就是app不需要像browser那样⽤cookie来保存session,因此⽤session token来标⽰⾃⼰就够了,session/state由api server的逻辑处理。如果你
的后端不是stateless的rest api,那么你可能需要在app⾥保存session.可以在app⾥嵌⼊webkit,⽤⼀个隐藏的browser来管理cookie session.
Session是⼀种HTTP存储机制,⽬的是为⽆状态的HTTP提供的持久机制。所谓Session认证只是简单的把User信息存储到Session⾥,因为SID的不可预测性,暂且认为是安全的。这是⼀种认证⼿段。⽽Token,如果指的是OAuth Token或类似的机制的话,提供的是认证和授权,认证是针对⽤户,授权是针对App。其⽬的是让某App有权利访问某⽤户的信息。这⾥的Token是唯⼀的。不可以转移到其它App上,也不可以转到其它⽤户上。转过来说Session。Session只提供⼀种简单的认证,即有此SID,即认为有此User 的全部权利。是需要严格保密的,这个数据应该只保存在站⽅,不应该共享给其它⽹站或者第三⽅App。所以简单来说,如果你的⽤户数据可能需要和第三⽅共享,或者允许第三⽅调⽤API接⼝,⽤Token。如果永远只是⾃⼰的⽹站,⾃⼰的App,⽤什么就⽆所谓了。
token就是令牌,⽐如你授权(登录)⼀个程序时,他就是个依据,判断你是否已经授权该软件;cookie就是写在客户端的⼀个txt⽂件,⾥⾯包括你登录信息之类的,这样你下次在登录某个⽹站,就会⾃动调⽤cookie⾃动登录⽤户名;session和cookie差不多,只是session是写在服务器端的⽂件,也需要在客户端写⼊cookie⽂件,但是⽂件⾥是你的浏览器编号.Session的状态是存储在服务器端,客户端只有session id;⽽Token的状态是存储在客户端。
Cookie保存在客户端浏览器中,⽽Session保存在服务器上。如果说Cookie机制是通过检查客户⾝上的“通⾏证”来确定客户⾝份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户⾝份。Session相当于程序在服务器上建⽴的⼀份客户档案,客户来访的时候只需要查询客户档案表就可以了

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。