普遍的回答:
- cookie和session的区别:cookie存储在客户端,session存储在服务器
- token的运作:用户使用用户名密码登录,服务端生成token,客户端每次请求都带上token,服务器再验证该token
深入思考:
- 为什么需要cookie和session? 他们又是什么?
- cookie存储的是什么?session存储的又是什么?
- cookie安全吗?存储在客户端会不会被轻易窃取
- session的方式有什么问题吗?为什么需要token?
- token的具体工作方式是什么?怎么感觉好像和session一样?
- token有什么优势
为什么会有cookie和session
因为HTTP是无状态协议。
无状态的意思是:HTTP协议不具备保存之前发送过的请求或响应的功能。每次的请求是相互独立的,第n次的请求结果和第n-1次、第n+1次的请求结果不会互相影响。服务器不会保存客户端的状态,客户端必须每次带上自己的状态去请求服务器。
早期的Web主要用于文档的浏览,所以不需要设计能保存用户状态信息的功能。但是随着互联网的飞速发展,各类交互式Web应用开始需要保持用户状态,如电商、社交等网站等,都需要保持用户的登录状态、购物车状态等进行交互。
这意味着如果服务器处理请求时需要上次请求的信息,客户端必须重传全部信息,这样可能导致每次连接传送的数据量巨增。
于是cookie和session就被用于解决HTTP无状态的问题。
cookie和session是什么
cookie
cookie是浏览器存储在本地的数据文件,对于用户而言是具体存在的。一般是从服务端接收到,然后保存在本地,当再次请求对应的网站,会带上该域名下的cookie。
Cookie的作用通俗的说就是当一个用户通过HTTP协议访问一个服务器的时候,这个服务器会将一些Key/Value键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器的时候,数据又被完整地带回给服务器。
由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用。cookie限制大小一般是4K,保证不会占据太多磁盘空间。另外出于对隐私安全的考虑,Cookie设计为不可跨域名。即www.google.com颁发的Cookie不会被提交到域名www.baidu.com,即使提交过去也不可用。
session
Cookie可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,这无形地增加了客户端与服务端的数据传输量。此外cookie保存在客户端,有被篡改、盗取的风险。而Session的出现正是为了解决这个问题。
所以单纯的以实现保存用户状态目的的话,只使用cookie也是可行的。其实在Cookie设计之初就是直接保存用户信息,但是由于cookie 是存在用户端,最关键是用户可以是可见的,并可以随意的修改,很不安全。所以session机制诞生了
session意为会话,主要作用是记录了用户会话相关的数据。
理论上:
- session 没有大小限制,所以,可以储存任意数量的数据
- session 没有类型限制,所以,可以储存任意类型的数据
- session 没有安全问题,所以,可以储存任意安全级别的数据
理论上session可以存储任何数据,但并不建议任何数据都保存在SESSION中。SESSION通常用来保存与特定用户信息相关的信息,如:身份信息、登陆状态、用户的个性配置、权限列表、其他的一些通用数据(比如购物车)。
通常我们把通用的、频繁存取的、小数据量的 跟用户相关的 数据放入SEESION。
同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie值,而是只要传回一个会话标识(SessionId),这个ID是客户端第一次访问服务器的时候生成的,而且每个客户端是唯一的。这样每个客户端就有一个唯一的ID,客户端只要传回这个ID就行了,这个ID通常是NAME为JSESIONID的一个Cookie。在Web服务器上,各个会话独立存储保存不同会话的信息。如果遇到禁用Cookie的情况,一般的做法就是把这个会话标识放到URL的参数中。
session机制
session机制是一种服务器端的机制,Session可以用Cookie来实现,也可以用URL回写的机制来实现。用Cookie来实现的Session可以认为是对Cookie更高级的应用。一般使用cookie来实现session。
session的运作
当客户端第一次访问服务器时,服务器创建一个session,同时生成一个唯一的会话key,即sessionID。接着sessionID及session分别作为key和value保存到缓存中,也可以保存到数据库中,然后服务器把sessionID以cookie的形式发送给客户端浏览器,浏览器下次访问服务器时直接携带上cookie中的sessionID,服务器再根据sessionID找到对应的session进行匹配。
总结:
- session由服务端产生
- 以字典的形式存储,session保存状态信息,sessionid返回给客户端保存至本地
- 服务端需要一定的空间存储session,且一般为了提高响应速度,都是存储在内存中
- sessionID会自动由浏览器带上
集群下的session
像我们个人搭的一些小型网站,可能一台服务器就足够应对用户的访问,所以我们的session可以存储我们的应用服务器上,就如同上图模型。但对于具有一定规模的网站,甚至是阿里、腾讯的网站,背后是千万台服务器在运作。那么集群下的session该管理?
如果用户的session信息只是存储在当前访问的服务器上,那么当负载均衡器把用户的下一个请求转发到另一个服务器,由于另一台服务器没有用户的 Session信息,那么该用户就需要重新进行登录等操作,显然是不够合理的。
1. sticky session
通过配置负载均衡器,使得一个用户的所有请求都路由到同一个服务器,这样就可以把用户的session存放在该服务器中。
例:
负载均衡时 对用户ip求哈希取余,从而保证同一个用户的请求最终都路由到同一个服务器
hash(ip) % 服务器台数
缺点:
- 当服务器宕机时,将丢失该服务器上所有的session
- 哈希函数和服务器台数会影响离散性质,即可能会导致负载不均匀
- 扩展性一般,当扩展机器台数时,用户可能会被路由到其他服务器(一致性哈希能缓解)
2. session replication
在服务器之间进行session同步操作,每个服务器都有所有用户的session信息,因此用户可以向任何一个服务器进行请求。
此方案不用再要求负载均衡器保证同一个会话的多次请求必须到同一个Web服务器上了。我们在Web服务器之间增加了会话数据的同步,通过同步就保证了不同Web服务器之间Session数据的一致。一般应用容器都支持Session Replication方式,与Session Sticky方案相比,Session Replication方式对负载均衡器没有那么多的要求。
存在问题:
- 同步Session数据造成了网络带宽的开销。只要Session数据有变化,就需要将数据同步到所有其他机器上,机器越多,同步带来的网络带宽开销就越大。
- 每台Web服务器都要保存所有Session数据,如果整个集群的Session数据很多(很多人同时访问网站)的话,每台机器用于保存Session数据的内容占用会很严重。
这个方案是靠应用容器来完成Session的复制从而解决Session的问题的,应用本身并不关心这个事情。这个方案不适合集群机器数多的场景。如果只有几台机器,用这个方案是可以的。
3. session server
使用一个单独的服务器存储session数据,可以使用传统的mysql或redis、memcached。
优点是使大型网站具有伸缩性,保证了应用服务器的无状态,session server将用户的会话信息单独进行存储。相对于Session Replication,当Web服务器数量比较大、Session数比较多的时候,这个集中存储方案的优势是非常明显的。
存在问题:
- 读写Session数据引入了网络操作,这相对于本机的数据读取来说,问题就在于存在时延和不稳定性,不过我们的通讯基本都是发生在内网,问题不大。
- 如果集中存储Session的机器或者集群有问题,就会影响到我们的应用。(即session服务器尽量保证高可用)
token是什么
对于 Token,在很多大型网站中都有所应用,比如 Facebook,Twitter,Google,Github 等等,比起传统的身份验证方法,Token 的扩展性更强,也更安全点,非常适合用在 Web 应用或者移动应用上。
先给一个非常熟悉的token场景:我们在A程序上准备登录账号,登录方式除了A程序注册的账号密码登录外,可以选择微信登录、QQ登录等等。如果我们选择微信登录,就会弹出微信页面,选择授权登陆以后,就会返回到A程序,微信登录成功!
那么这个过程token是如何参与其中的呢?在这里,我们可以先把token暂时模拟成cookie,它能让我们不需要输入用户名密码而保持登录状态。
这里有一个关键点,就是跨域。我们常用的cookie只能是按域名发送对应的cookie,不能实现跨域的功能。这也是为什么会出现token的原因之一。
如果token或sessionid被盗取,服务器都无法辨识。在网络层面上使用明文传输的话是非常危险的,所以一定要使用HTTPS协议。
token和session的区别
token和session功能相似,那为什么会有token呢?普通cookie和session机制的问题:
- 服务器需要记录每个用户的状态信息,内存开销大
- 多机session问题,扩展性差
- CORS(跨域资源共享):当我们需要让数据跨多台移动设备上使用时,跨域资源共享难。
- CSRF(跨站请求伪造):用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够被利用其访问其他的网站。
基于Token的身份验证是无状态的,我们不将用户信息存在服务器中。这种概念解决了在服务端存储信息时的许多问题。NoSession意味着你的程序可以根据需要去增减机器,而不用去担心用户是否登录,不用去担心扩展性的问题。
其实token与session的问题是一种时间与空间的博弈问题,session是空间换时间,而token是时间换空间。两者的选择要看具体情况而定。
token 和 session 本质功能相似,但如果跨站使用,token 会更方便一些。以下几点特性也会让你在程序中使用基于Token的身份验证:
- 无状态、可扩展
- 支持移动设备
- 跨程序调用
- 安全
token更多是对用户进行认证,然后对某一个应用进行授权。让某个应用拥有用户的部分信息。这个token仅供此应用使用。
session像是这个用户登录了应用,用户把全部信息存放在此应用,应用拥有完整的用户信息。
所以session和 token并不矛盾,作为身份认证token安全性比session好,因为每个请求都有签名还能防止监听以及重放攻击,而session就必须靠链路层来保障通讯安全了。如上所说,如果你需要实现有状态的会话,仍然可以增加session来在服务器端保存一些状态。
Session是一种HTTP存储机制,目的是为无状态的HTTP提供的持久机制。所谓Session认证只是简单的把User信息存储到Session里,因为SID的不可预测性,暂且认为是安全的。这是一种认证手段。
而Token,如果指的是OAuth Token或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对App。其目的是让 某App有权利访问 某用户 的信息。这里的Token是唯一的。不可以转移到其它App上,也不可以转到其它 用户 上。
Session只提供一种简单的认证,即有此SID,即认为有此User的全部权利。是需要严格保密的,这个数据应该只保存在站方,不应该共享给其它网站或者第三方App。所以简单来说,如果你的用户数据可能需要和第三方共享,或者允许第三方调用API接口,用Token。如果永远只是自己的网站,自己的App,用什么就无所谓了。
token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件;cookie就是写在客户端的一个txt文件,里面包括你登录信息之类的,这样你下次在登录某个网站,就会自动调用cookie自动登录用户名;
session和cookie差不多,只是session是写在服务器端的文件,也需要在客户端写入cookie文件,但是文件里是你的浏览器编号.Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。
token的运作
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
- 客户端使用用户名跟密码请求登录;
- 服务端收到请求,去验证用户名与密码;
- 验证成功后,根据传过来的唯一标识userId(也可以是mac地址等唯一标识),服务端会通过一些算法,如常用的HMAC-SHA256算法,然后加一个密钥,生成一个token,然后通过BASE64编码一下之后将这个token发送给客户端;
- 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里;(通过js代码写入Local Storage,通过js获取,并不会像cookie一样自动携带)
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token;
- 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据。
补充:为什么需要加盐
简单的哈希加密算法不够安全,虽然是不可逆的,反向算出来困难,但是如果反向查询,密码设置的简单,也很容易被攻破。比如我们使用 md5 加密一个密码 123456,对应的 md5 是 e10adc3949ba59abbe56e057f20f883e,找到一个 md5 解密的网站,比如 cmd5.com/ ,很容易就被破解了密码…
由于简单的哈希存在被反向查询破解的问题,所以可以采用加盐的方式。这种方式算是给用户的隐私数据加上密了,其实就是一段隐私数据加一段乱码再进行哈希。但这是比较早期的处理方式,仍存在一定的问题。
- 存在泄漏的可能:盐一般采用硬编码,如果源码泄露或是内部人员泄漏,都会产生很大的安全问题。(这也是盐最大的缺陷)
- 依赖性太强:盐一旦被设定,再想做修改就非常困难,因为服务器存储的都是加盐后的数据,如果更换盐,则所有数据都需要改动。
tokens的优势
对比cookie session的好处
- 支持跨域访问:
Cookie是不允许垮域访问的
(垮域访问:两个域名之间不能跨过域名来发送请求或者请求数据)
- 无状态(也称:服务端可扩展行):
Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息
只需要在客户端的cookie或本地介质存储状态信息.
基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。
- 更适用CDN:
可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
- 去耦:
不需要绑定到一个特定的身份验证方案。
Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
- 更适用于移动应用:
当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理)
这时采用Token认证机制就会简单得多。
6.安全性
请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。
即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。
不将信息存储在Session中,让我们少了对session操作。
token是有时效的,一段时间之后用户需要重新验证。
- 性能:
一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
(内存型的session另说)
- 基于标准化:
你的API可以采用标准化的 JSON Web Token (JWT).
这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).
token的思想是算法验证,session的思想是信息存储对比。token是有多种方案的,可以设计成无需存储,token同时也是跨域的,session是要存储的,存储在数据库的思想。token存储是为了以后设计一个动态的跨域验证方案。例子:用redis实现动态token存储,还可以跨域访问,实现系统分离。
有效期
需要设置有效期吗?
对于这个问题,我们不妨先看两个例子。一个例子是登录密码,一般要求定期改变密码,以防止泄漏,所以密码是有有效期的;另一个例子是安全证书,SSL 安全证书都有有效期,目的是为了解决吊销的问题。所以无论是从安全的角度考虑,还是从吊销的角度考虑,Token 都需要设有效期。
那么有效期多长合适呢?
只能说,根据系统的安全需要,尽可能的短,但也不能短得离谱
然后新问题产生了,如果用户在正常操作的过程中,Token 过期失效了,要求用户重新登录……用户体验岂不是很糟糕?
为了解决在操作过程不能让用户感到 Token 失效这个问题,有一种方案是在服务器端保存 Token 状态,用户每次操作都会自动刷新(推迟) Token 的过期时间——Session 就是采用这种策略来保持用户登录状态的。然而仍然存在这样一个问题,在前后端分离、单页 App 这些情况下,每秒种可能发起很多次请求,每次都去刷新过期时间会产生非常大的代价。如果 Token 的过期时间被持久化到数据库或文件,代价就更大了。所以通常为了提升效率,减少消耗,会把 Token 的过期时保存在缓存或者内存中。
还有另一种方案,使用 Refresh Token,它可以避免频繁的读写操作。这种方案中,服务端不需要刷新 Token 的过期时间,一旦 Token 过期,就反馈给前端,前端使用 Refresh Token 申请一个全新 Token 继续使用。这种方案中,服务端只需要在客户端请求更新 Token 的时候对 Refresh Token 的有效性进行一次检查,大大减少了更新有效期的操作,也就避免了频繁读写。当然 Refresh Token 也是有有效期的,但是这个有效期就可以长一点了,比如,以天为单位的时间。
token的其他应用
令牌,最大的特点就是随机性,不可预测。一般黑客或软件无法猜测出来。
Token一般用在两个地方:
- 防止表单重复提交、
- anti csrf攻击(跨站点请求伪造)。
两者在原理上都是通过session token来实现的。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,Token会随着表单一起提交到服务器端。
然后,如果应用于“anti csrf攻击”,则服务器端会对Token值进行验证,判断是否和session中的Token值相等,若相等,则可以证明请求有效,不是伪造的。
不过,如果应用于“防止表单重复提交”,服务器端第一次验证相同过后,会将session中的Token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的Token没变,但服务器端session中Token已经改变了。
上面的session应用相对安全,但也叫繁琐,同时当多页面多请求时,必须采用多Token同时生成的方法,这样占用更多资源,执行效率会降低。因此,也可用cookie存储验证信息的方法来代替session Token。比如,应对“重复提交”时,当第一次提交后便把已经提交的信息写到cookie中,当第二次提交时,由于cookie已经有提交记录,因此第二次提交会失败。
不过,cookie存储有个致命弱点,如果cookie被劫持(xss攻击很容易得到用户cookie),那么又一次gameover。黑客将直接实现csrf攻击。
所以,安全和高效相对的。具体问题具体对待吧。
此外,要避免“加token但不进行校验”的情况,在session中增加了token,但服务端没有对token进行验证,根本起不到防范的作用。
还需注意的是,对数据库有改动的增删改操作,需要加token验证,对于查询操作,一定不要加token,防止攻击者通过查询操作获取token进行csrf攻击。但并不是这样攻击者就无法获得token,只是增大攻击成本而已。
名称解释:
[1] XSS 攻击:
跨站脚本攻击(Cross Site Scripting),恶意攻击者往 Web 页面里插入恶意 Script 代码,当用户浏览该页之时,嵌入其中 Web 里面的 Script 代码会被执行,从而达到恶意攻击用户的目的。
[2] CSRF 攻击:
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者 Session Riding,通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。
尽管听起来像跨站脚本(XSS),但它与 XSS 非常不同,XSS 利用站点内的信任用户,而 CSRF 则通过伪装来自受信任用户的请求来利用受信任的网站。
与 XSS 攻击相比,CSRF 攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比 XSS 更具危险性。
引用
https://www.jianshu.com/p/c9017df96869
https://www.cnblogs.com/moyand/p/9047978.html
https://blog.csdn.net/u010902804/article/details/81182223
https://www.jianshu.com/p/3104e83dea8d
https://blog.csdn.net/qq_35246620/article/details/55049812
https://www.jianshu.com/p/de22230b7b80