会话技术及用户认证-Cookie、Session与 Token

前言

最早互联网只是用于简单的浏览文档信息、查看黄页及门户网站等等,并没有交互这个说法。但是随着互联网慢慢发展,宽带、服务器等硬件设施得到了很大的提示,互联网允许人们可以做更多的事情,所以交互式Web逐渐兴起,而HTTP无状态的特点却严重阻碍了其发展。
HTTP 是无状态的协议,每个请求都是完全独立的(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息)。也就是说,无法根据之前的状态进行本次的请求处理——服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。
因此,服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。

Cookie

在1994年,网景公司将Cookie的概念应用于网络通信,用来解决用户网上购物的购物车历史记录问题。而当时最强大的浏览器正是网景浏览器,在其支持下,其它浏览器也渐渐开始支持Cookie,到目前当然所有的浏览器都支持Cookie了。

既然Web服务器记不住东西,那么我们就在外部想办法记住,相当于服务器给每个客户端都贴上了一个小纸条。上面记录了服务器给我们返回的一些信息。然后服务器看到这张小纸条就知道我们是谁了,这个小纸条也就是Cookie。

Cookie是由服务器产生的而保存在客户端的一些数据,一般通过HTTP响应头Set-Cookie来设置,当然也可以通过JS脚本来直接设置,Cookie是按照网站来进行组织和保存的,每一个网站都可以在浏览器中保存一些Cookie,保存好了之后,浏览器向这个网站发出的请求都会携带这些Cookie,用于服务器记录客户端的状态。
例如,当我们登录网站勾选保存用户名和密码的时候,一般保存的都是cookie,将用户名和密码的cookie保存下来,这样再次登录的时候浏览器直接将cookie发送到服务端验证,直接username和password保存到客户端;再比如用户喜欢的网页背景色,这些信息也是可以通过Cookie保存到客户端的,这样登录之后直接浏览器直接就可以拿到相应的偏好设置。
Cookie主要用于以下三个方面:

  • 会话状态管理:如用户登陆状态、购物车商品或其它需要记录的信息
  • 个性化设置:如用户自定义设置、主题等
  • 浏览器行为跟踪:如跟踪分析用户行为等

构成

cookie遵循name=value格式的字符串形式,并且单个cookie保存的数据不能超过4K(很多浏览器都限制一个站点最多保存20个cookie)。主要构成有:

name: 一个唯一确定的cookie名称,服务器就是通过name属性来获取某个cookie值。通常来讲cookie的名称是不区分大小写的。

value: 存储在cookie中的字符串值,大多数情况下服务器会把这个value当作一个key取缓存中查询保存的数据。最好为cookie的name和value进行url编码

domain: cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。顶级域名(如 .baidu.com)只能设置或访问顶级域名的Cookie,二级及二级以下域名( tieba.baidu.com)可以访问或设置自身或者顶级域名的Cookie(也就是说,如果要在多个二级域名中共享Cookie,只能将domain属性设置为顶级域名)。

path:  表示这个cookie影响到的路径,浏览器跟会根据这项配置,像指定域中匹配的路径发送cookie(只有该路径下的页面可以读取此cookie)。

expires: 失效时间,表示cookie何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。如果不设置这个时间戳,浏览器会在页面关闭时即将删除所有cookie;不过也可以自己设置删除时间。这个值是GMT时间格式,如果客户端和服务器端时间不一致,使用expires就会存在偏差。

max-age:  与expires作用相同,用来告诉浏览器此cookie多久过期(单位是秒),而不是一个固定的时间点。正常情况下,max-age的优先级高于expires。

HttpOnly:  告知浏览器不允许通过脚本document.cookie去更改这个值,同样这个值在document.cookie中也不可见。但在http请求张仍然会携带这个cookie。注意这个值虽然在脚本中不可获取,但仍然在浏览器安装目录中以文件形式存在。这项设置通常在服务器端设置。

secure:  安全标志,指定后,只有在使用SSL链接时候才能发送到服务器,如果是http链接则不会传递该信息。就算设置了secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息,所以不要把重要信息放cookie就对了。

会话cookie和持久cookie

cookie有过期时间设定。
如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。
如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。
存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。

Session

Cookie是存在客户端,且其本身存储的尺寸大小有限,最关键的问题是Cookie是用户可见的,并可以随意地修改,安全性存在很大问题。为了安全又方便地全局读取信息,一种新的存储会话机制——Session诞生了。
session是服务端存储的一个对象,主要用来存储所有访问过该服务端的客户端的用户信息(也可以存储其他信息),从而实现保持用户会话状态。但是服务器重启时,内存会被销毁,存储的用户信息也就消失了。
不同的用户访问服务端的时候会在session对象中存储键值(key-vaule)对,key是用来存储开启这个用户信息的“钥匙”,在登录成功后,“钥匙”通过cookie返回给客户端,客户端存储为session Id记录在cookie中。当客户端再次访问时,会默认携带cookie中的session Id来实现会话机制。
简单来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时由于在服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的。

 

 

Session认证流程

  • 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session
  • 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器
  • 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
  • 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。

若浏览器禁止cookie,可以通过URL重写的方式发送:把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

分布式架构下 session 共享方案

Session的数据一般是存储到内存中,那问题就来了,如果我们的服务是分布式部署,有多台机器的话,可能我们第一次登陆的时候,我们把用户的信息存储到了session,但是后面的请求到了B机器上,那B机器是获取不到用户的session的。另外就是Session存储在内存中,那服务器重启,Session就丢失了,这就是它的弊端。现在有一些技术可以解决上述问题。
1. session 复制
任何一个服务器上的 session 发生改变(增删改),该节点会把这个 session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 session ,以此来保证 session 同步。

  • 优点: 可容错,各个服务器间 session 能够实时响应。
  • 缺点: 会对网络负荷造成一定压力,如果 session 量大的话可能会造成网络堵塞,拖慢服务器性能。

2. 粘性 session /IP 绑定策略
采用 Ngnix 中的 ip_hash 机制,将某个 ip的所有请求都定向到同一台服务器上,即将用户与服务器绑定。 用户第一次请求时,负载均衡器将用户的请求转发到了 A 服务器上,如果负载均衡器设置了粘性 session 的话,那么用户以后的每次请求都会转发到 A 服务器上,相当于把用户和 A 服务器粘到了一块,这就是粘性 session 机制。

  • 优点: 简单,不需要对 session 做任何处理。
  • 缺点: 缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的 session 信息都将失效。
  • 适用场景: 发生故障对客户产生的影响较小;服务器发生故障是低概率事件 。
  • 实现方式: 以 Nginx 为例,在 upstream 模块配置 ip_hash 属性即可实现粘性 session。

3. session 共享(常用)
使用分布式缓存方案比如 Memcached 、Redis 来缓存 session,但是要求 Memcached 或 Redis 必须是集群。把 session 放到 Redis 中存储,虽然架构上变得复杂,并且需要多访问一次 Redis ,但是这种方案带来的好处也是很大的:

  • 实现了 session 共享;
  • 可以水平扩展(增加 Redis 服务器);
  • 服务器重启 session 不丢失(不过也要注意 session 在 Redis 中的刷新/失效机制);
  • 不仅可以跨服务器 session 共享,甚至可以跨平台(例如网页端和 APP 端)

4. session 持久化
将 session 存储到数据库中,保证 session 的持久化

  • 优点: 服务器出现问题,session 不会丢失
  • 缺点: 如果网站的访问量很大,把 session 存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。

Cookie和Session的区别

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上,当访问增多,会比较占用服务器的性能。考虑到减轻服务器负担方面,应当使用cookie。
4、存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。

因此,通常的做法是,将登陆信息等重要信息存放为session,而其他信息如果需要保留,可以放在cookie中。

Token

session 是保存了会话的链接信息与需要传输的内容,容量大,还需要保持会话信息,每次同一用户不同客户端访问都需要重新建立session,造成冗余信息大。
Token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。

 

 

token 的身份验证流程

1、客户端使用用户名跟密码请求登录
2、服务端收到请求,去验证用户名与密码
3、验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
4、客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 LocalStorage 里
5、客户端每次向服务端请求资源的时候需要带着服务端签发的 token
6、服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据
在这个过程中,每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里。
基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库。token 完全由应用管理,所以它可以避开同源策略。

Token 和 Session 的区别

1、Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。
2、Session 和 Token 并不矛盾,作为身份认证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重放攻击,而 Session 就必须依赖链路层来保障通讯安全了。如果你需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态。
3、所谓 Session 认证只是简单的把 User 信息存储到 Session 里,因为 SessionID 的不可预测性,暂且认为是安全的。而 Token ,如果指的是 OAuth Token 或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对 App 。其目的是让某 App 有权利访问某用户的信息。这里的 Token 是唯一的。不可以转移到其它 App上,也不可以转到其它用户上。Session 只提供一种简单的认证,即只要有此 SessionID ,即认为有此 User 的全部权利。是需要严格保密的,这个数据应该只保存在站方,不应该共享给其它网站或者第三方 App。

Token的特点

Token的特点
• 随机性:每次的token都是不一样的
• 不可预测性:没有规律,无法预测
• 时效性: 可以设置token的有效时间
• 无状态、可扩展:由于只是一个算法,扩展起来非常方便
生成Token的解决方案有许多,常用的一种就是 JSON Web Token(JWT) .

JWT

JWT是目前最流行的跨域认证解决方案,可以使用在RESTFUL接口定义,也可以使用在普通的web。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。
JWT标准的Token由三部分组成:Header头部,Payload负载和Signature签名,三部分之间用“.”号做分割。
1、Header 声明信息。 在Header中通常包含了两部分:type:代表token的类型,这里使用的是JWT类型。 alg:使用的Hash算法,例如HMAC SHA256或RSA。{ “alg”: “HS256”, “typ”: “JWT” } 这会被经过Base64 URL编码形成第一部分

2、Payload token的第二个部分是荷载信息,它包含一些声明Claim(实体的描述,通常是一个User信息,还包括一些其他的元数据) 声明分三类: 
1)Reserved Claims:这是一套预定义的声明,并不是必须的,这是一套易于使用、操作性强的声明。包括:iss(issuer)、exp(expiration time)、sub(subject)、aud(audience)等 
2)Plubic Claims
3)Private Claims:交换信息的双方自定义的声明 { “sub”: “1234567890”, “name”: “John Doe”, “admin”: true } 
默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息(当然加密也没问题)加密的话推荐使用RSA加密。JSON对象也使用Base64 URL算法转换为字符串保存。

3、Signature 使用header中指定的算法将编码后的header、编码后的payload、一个secret进行加密。 例如使用的是HMAC SHA256算法,大致流程类似于: HMACSHA256( base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret) 。这个signature字段被用来确认JWT信息的发送者是谁,并保证信息没有被修改 。

验证流程:

1. 在头部信息中声明加密算法和常量, 然后把header使用json转化为字符串
2. 在载荷中声明用户信息,同时还有一些其他的内容;再次使用json 把载荷部分进行转化,转化为字符串
3. 使用在header中声明的加密算法和每个项目随机生成的secret来进行加密, 把第一步分字符串和第二部分的字符串进行加密, 生成新的字符串,此字符串是独一无二的。
4. 解密的时候,只要客户端带着JWT来发起请求,服务端就直接使用secret进行解密;解签证解出第一部分和第二部分,然后比对第二部分的信息和客户端穿过来的信息是否一致。如果一致验证成功,否则验证失败。

常见问题总结补充

使用 cookie 时需要考虑的问题

  • 因为存储在客户端,容易被客户端篡改,使用前需要验证合法性
  • 不要存储敏感数据,比如用户密码,账户余额
  • 使用 httpOnly 在一定程度上提高安全性
  • 尽量减少 cookie 的体积,能存储的数据量不能超过 4kb
  • 设置正确的 domain 和 path,减少数据传输
  • cookie 无法跨域
  • 一个浏览器针对一个网站最多存 20 个Cookie,浏览器一般只允许存放 300 个Cookie
  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

使用 session 时需要考虑的问题

  • 将 session 存储在服务器里面,当用户同时在线量比较多时,这些 session 会占据较多的内存,需要在服务端定期的去清理过期的 session
  • 当网站采用集群部署的时候,会遇到多台 web 服务器之间如何做 session 共享的问题。因为 session 是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建 session 的服务器,那么该服务器就无法拿到之前已经放入到 session 中的登录凭证之类的信息了。
  • 当多个应用要共享 session 时,除了以上问题,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好 cookie 跨域的处理。
  • sessionId 是存储在 cookie 中的,假如浏览器禁止 cookie 或不支持 cookie 怎么办? 一般会把 sessionId 跟在 url 参数后面即重写 url,所以 session 不一定非得需要靠 cookie 实现
  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

使用 token 时需要考虑的问题

  • 如果你认为用数据库来存储 token 会导致查询时间太长,可以选择放在内存当中。比如 redis 很适合你对 token 查询的需求。
  • token 完全由应用管理,所以它可以避开同源策略
  • token 可以避免 CSRF 攻击(因为不需要 cookie 了)
  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

JWT相关

  • 因为 JWT 并不依赖 Cookie 的,所以你可以使用任何域名提供你的 API 服务而不需要担心跨域资源共享问题(CORS)
  • JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
  • JWT 不加密的情况下,不能将秘密数据写入 JWT。
  • JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
  • JWT 最大的优势是服务器不再需要存储 Session,使得服务器认证鉴权业务可以方便扩展。但这也是 JWT 最大的缺点:由于服务器不需要存储 Session 状态,因此使用过程中无法废弃某个 Token 或者更改 Token 的权限。也就是说一旦 JWT 签发了,到期之前就会始终有效,除非服务器部署额外的逻辑。
  • JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
  • JWT 适合一次性的命令认证,颁发一个有效期极短的 JWT,即使暴露了危险也很小,由于每次操作都会生成新的 JWT,因此也没必要保存 JWT,真正实现无状态。
  • 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CookieSessionToken 是用于网络应用程序身份验证和授权的不同技术Cookie 是由网站发送到用户浏览器并存储在其中的小型文本文件。它们可以被用来跟踪用户会话,并在用户再次访问网站时自动登录。 Session 是服务器端的一种存储方式,用于在用户登录后跟踪用户会话。当用户登录时,服务器会为用户创建一个 session,并在其中存储信息。每当用户在网站上请求页面时,浏览器都会把 session ID 传回服务器,这样服务器就可以识别用户并访问该用户相关的信息。 Token 是一种用于身份验证和授权的机制。当用户登录时,服务器会为用户生成一个 token,并将其发送回用户。以后,用户可以在请求中提供此 token,以证明其身份。与 session 不同,token 不会存储在服务器上,而是由客户端保存在内存或本地存储中。 总结来说,CookieSession 都是用于在客户端和服务器端之间存储信息的技术,用于维护用户状态,而 Token 是一种无状态的验证机制,用于验证用户身份。 CookieSession 都是在服务器端存储信息的技术,而 Token 是客户端存储信息的技术Cookie 通常存储在浏览器中,通过在 HTTP 请求头中传递给服务器,而 Session 通常存储在服务器的内存中,通过 Session ID 来识别用户Token 通常存储在客户端中,比如本地存储或内存中,通过在请求头中传递给服务器,来证明用户身份。 另外,CookieSession 都是在用户登录后跟踪用户会话的方式,而 Token 是登录后通过用户请求验证身份的方式。 在选择使用哪种方式时,需要考虑多种因素,包括安全性,性能,用户体验等。 例如: 如果需要支持多设备同时登录,则使用 token 方式更好一些,因为他是无状态的。但如果需要兼顾性能和安全性,则使用Cookie+Token的方式更好。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值