这一次,把
Cookie
,Session
,Token
弄清楚!
【主要内容来自网络🤣,其实这几个东西理解了就没啥了,主要是要用起来,我看到许多同行,大佬介绍的很好,也就采用了拿来主义
(之所以标记原创是因为参考文章较多)】
这三个其实是有关联的概念或者说技术,建议大家通篇阅读后理解。
Cookie
前言
http是一个无状态的协议(特指1.x),意思就是服务器不知道某个请求是哪个客户端发送的,
更不知道某一个客户端第几次发的了,Cookie便是解决了这样的问题
推荐一篇文章:【知乎】 HTTP是一个无状态的协议。这句话里的无状态是什么意思?
Cookie
的大部分内容均来自
Cookie
是一个请求首部,其中含有先前由服务器通过 Set-Cookie 首部投放并存储到客户端的 HTTP cookies。-------MDN
共享
在 Web 开发中,cookie 的共享规则涉及到协议、端口和域名的设置。具体来说,cookie 的共享规则如下:
-
域名:
- 默认情况下,cookie 仅在设置它的域名及其子域名下共享。例如,如果一个 cookie 在
example.com
设置,那么sub.example.com
也能访问到这个 cookie,但anotherexample.com
无法访问。 - 可以通过设置
Domain
属性来指定 cookie 可以共享的域。例如,设置Domain=.example.com
,cookie 将在example.com
及其所有子域(如sub.example.com
和another.sub.example.com
)之间共享。
- 默认情况下,cookie 仅在设置它的域名及其子域名下共享。例如,如果一个 cookie 在
-
路径:
- Cookie 仅在设置它的路径及其子路径下共享。例如,如果 cookie 在
/path/
设置,那么/path/subpath/
也能访问到这个 cookie,但/anotherpath/
无法访问。 - 可以通过设置
Path
属性来指定 cookie 可以共享的路径。
- Cookie 仅在设置它的路径及其子路径下共享。例如,如果 cookie 在
-
协议:
- Cookie 可以在 HTTP 和 HTTPS 之间共享,但前提是没有设置
Secure
标志。如果设置了Secure
标志,cookie 只能通过 HTTPS 传输。
- Cookie 可以在 HTTP 和 HTTPS 之间共享,但前提是没有设置
-
端口:
- Cookie 与端口无关。只要域名和路径符合要求,并且协议(如果有
Secure
标志)匹配,cookie 就可以共享。
- Cookie 与端口无关。只要域名和路径符合要求,并且协议(如果有
举个例子:
Set-Cookie: name=value; Domain=.example.com; Path=/; Secure; HttpOnly
这个 cookie 将在 example.com
及其所有子域(如 sub.example.com
)上共享,并且只会在 HTTPS 连接上发送,同时无法通过 JavaScript 访问(由于 HttpOnly
标志)。
如何设置的
- 客户端发送请求到服务器
- 服务器收到响应后,在响应头添加一个
Set-Cookie
字段 - 浏览器收到响应后保存
Cookie
- 之后每次向该服务器的请求都自动携带
Cookie
字段的Cookie
Cookies 相关的一些属性
Name/Value
这个表示Cookie的键/值
用 JavaScript 操作 Cookie 的时候注意对 Value 进行编码处理。
document.cookie = "name=cookie; Expires=2021-02-28T07:23:08.432Z"
Expires
用于设置 Cookie
的过期时间(UTC时间),缺省时,缺省时为会话 Cookie
,仅当浏览器关闭时才会消失(刷新不会消失)
document.cookie=`name=cookie-data;expires=${new Date(2021,8,1).toGMTString()}`
还有一种 Cookie
是持久性 Cookie
, 保存在用户的硬盘中,等到过期或者主动清除才会消失,并且设定的日期和时间客户端有关,而非服务器。
具体路径:
Max-Age
用于设置 Cookie
失效之前经过的秒数,
// 设置一个10s后消失的cookie
document.cookie = "name=cookie; Max-Age=10"
注意,检测有没有Cookie
不要刷新浏览器(会重新设置),控制台有一个刷新按钮
Max-Age
可以设置正数,负数,0
情况 | 效果 |
---|
0 | 持久化,存入磁盘,到响应的时间才消失
< 0 | 是一个会话``cookie, 关闭浏览器消失 0 | 立即消失 存在
Expires|
Max-Age` 优先级更高
Domain
指定 Cookie
可以送达的主机名,默认为当前访问的 url 根路径(不含子域名)。
当然,不能跨域设置Cookie;
如果Domain设置为
document.cookie = "name=cookie; Max-Age=10000; Domain=.taobao.com"
那么 a.taobao.com
与 b.taobao.com
均可使用该 Cookie
Path
指定一个请求的Url路径,若有如下设置
document.cookie = "name=cookie; Max-Age=10000; Path=/Cookie"
那么在 /Cookie
以及其子路由 /Cookie/a
下的资源会携带Cookie首部,而 /otherpath
则不会携带
Domain 和 Path 标识共同定义了 Cookie 的作用域:即 Cookie 应该发送给哪些 URL。
Secure
当设置此属性时,该 Cookie
只能被 Https
协议携带发送至服务器。Secure
, 见名思意,被https发送的请求保证内容在传输过程不会被 窃取/篡改
HttpOnly
服务端设置了此属性之后,客户端脚本(JS)就不能通过 document.cookie
访问了,避免了 XSS攻击
SameSite
这是新增的属性。取值包括:Lax
(默认), None
, Strict
(80之前默认是None
)
值得一提的事件:【百度】 新版chrome(80+)浏览器默认屏蔽所有三方cookie
值 | 效果 |
---|---|
Strict | 严格模式,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标完全一致,才会带上 Cookie |
Lax | 允许部分第三方请求携带 Cookie |
None | 关闭 SameSite 属性,前提是必须同时设置 Secure 属性(Cookie 只能通过 HTTPS 协议发送),否则无效 |
SameSite 属性可以让 Cookie 在跨站【参考后面补充】请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF) |
用node 代理解决这个问题 传送门
Cookie的属性介绍基本就结束了。
补充
跨域和跨站
此部分重点抄袭原文
同源策略是浏览器的安全基石,同源即协议(http/https)、域名(例baidu.com)、端口(例如2434)完全系统。相对而言,Cookie
中的「同站」判断就比较宽松:只要两个 URL 的 eTLD+1 相同即可,不需要考虑协议和端口。其中,eTLD 表示有效顶级域名,注册于 Mozilla 维护的公共后缀列表(Public Suffix List)中,例如,.com
、.co.uk
、.github.io
等。eTLD+1 则表示,有效顶级域名+二级域名,例如 taobao.com
等
举几个例子,www.taobao.com
和 www.baidu.com
是跨站,www.a.taobao.com
和 www.b.taobao.com
是同站,a.github.io
和 b.github.io
是跨站(注意是跨站)。
None 改成 Lax 到底影响了哪些地方的 Cookies
的发送
HTTP 接口不支持 SameSite=none
Cookie 的作用:
Cookie 主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
Cookie 的缺点:
可以从大小、安全、增加请求大小。
最后
JS 对Cookie 操作的库有很多, 推荐 [js-cookie]
Session
主要内容来自
开门见山
session
从字面上讲,就是会话。服务器要对每个客户端身份进行区分,所以对其发放“身份标识”,每次客户端向服务端请求会带上这个“身份标识”。对于浏览器客户端,大家一般都采用 cookie
的方式。
客户端和服务端会话过程
cookie & session
cookie
和 session
的方案虽然分别属于客户端和服务端,但是服务端的 session
的实现对客户端的 cookie
有依赖关系的;步骤大概如下:
- 服务端执行
Session
机制 - 生成对应而唯一的
session_id
(通过对这个session_id
的解析和处理,服务端可以找到,该session
保存的文件;再从文件中提取出session
的信息) - 服务端会将这个
session_id
发送给客户端 - 客户端接受到
session_id
,以cookie
作为保存的容器保存起来 - 客户端在每次请求的时候都会带这个
session_id
给服务端 - 服务端自行解析
session
注意:session
保存信息的手段是多种的:缓存,数据库,文件等;但是默认是文件形式保存。。。
session
是一个概念,是一个数据对象,用来存储访问者的信息。session
的存储方式由开发者自己定义,可存于内存,redis
,mysql
,甚至是cookie
中。- 用户第一次访问的时候,我们就会给用户创建一个他的
session
,并在cookie
中塞一个他的 “钥匙key” 。所以即使http
请求 是无状态的,但通过cookie
我们就可以拿到访问者的 “钥匙key” ,便可以从所有访问者的session
集合中取出对应访问者的session
。- 关闭浏览器,服务端的
session
是不会马上过期的。session
中间件自己实现了一套管理方式,当访问间隔超过maxAge
的时候,session
便会失效。
cookie&session区别
- 安全性。因为
Cookie
可以通过客户端修改,而Session
只能在服务端设置,所以安全性比Cookie
高,一般会用于验证用户登录状态 - 适用性。
Cookie
只能存储字符串数据,而Session
可以存储任意类型数据 - 有效期。
Cookie
可以设置任意时间有效,而Session
一般失效时间短 - 继承性。一般客户端设置
Cookie
,如果要用于验证就需要服务端创建Session
Token
主要内容来自
基本概念
Token
是访问资源接口(API)时所需要的资源凭证。与 Session
相比,token
的优点是不需要存储数据在服务端,服务端只需要根据客户端传来的 token
进行合法验证,通过后端返回请求资源即可,减轻了服务端的资源占用压力.
目前最流行的跨域认证解决方案 JWT (JSON WEB TOKEN) 就是基于 token
实现(后面介绍)
token
其实就是一个数字签名
一般是在用户登录请求时,服务器响应返回token
,客户端存起来,在需要 token
的请求是带上传给服务器,后台校验 token
是否一致然后给出响应。
这能抵御 使用 cookie
可能出现的 跨请求伪造
(CSRF攻击),有个Cookie
新属性 SameSite
也能避免这个问题
关于JWT
JWT 认证流程:
- 客户端发送用户信息给服务端请求登录
- 服务端验证用户信息,验证通过后签发一个
Token
返回给客户端,客户端收到后会存储在Cookie
或localStorage
中 - 客户端继续第二次业务请求,请求头的
Authorization
字段携带这个Token
或者直接放在Cookie
(但是这样就不能跨域了) - 服务端根据
headers
中的Token
进行验证,验证通过后返回业务请求的数据
JWT
的优点:
- 可用于应用管理,避开同源策略
- 避免 CSRF 攻击
- 实现无状态服务端,能够在多个服务间使用,可扩展性好