HTTP 协议是一个无状态协议
HTTP是无状态的:在同一个连接中,两个执行成功的请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。
Cookie
既然 Web 服务器记不住东西,那么我们就在外部想办法记住。
以电商网站为例,当我们(客户端浏览器)第一次访问电商网站(服务端)时,电商网站给我们发放一张记录独特身份标识数据「会员卡」,格式为 <cookie名>=<cookie值>
,放入到 Set-Cookie
字段里(即在响应头里面添加一个 Set-Cookie
选项),随着响应报文发给浏览器
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: test_cookie=test
[页面内容]
浏览器接收到「会员卡」字段以后就把这张「会员卡」保存起来。(以 Chrome 浏览器为例,可以打开浏览器控制台 -> Application
-> Cookies
查看Cookie)
下次请求时浏览器会自动将此「会员卡」值放入到 Cookie
字段中发给服务端。
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: test_cookie=test
服务端收到请求报文后,发现Cookie字段中有值,就能根据此值识别用户的身份然后提供个性化的服务。
Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。
Cookie 保存在客户端中,按在客户端中的存储位置,可分为内存 Cookie 和硬盘 Cookie。内存 Cookie 由浏览器维护,保存在内存中,浏览器关闭即消失,存在时间短暂。硬盘 Cookie 保存在硬盘里,有过期时间,除非用户手动清理或到了过期时间,硬盘Cookie不会清除,存在时间较长。所以,按存在时间,可分为非持久 Cookie 和持久 Cookie 。
Cookie 主要用途
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
Cookie 语法
Cookie: <cookie-list>
<cookie-list>
:一系列的名称/值对,形式为 <cookie-name>=<cookie-value>
。名称/值对之间用分号和空格 (‘; ‘)隔开。设置 Cookie 的名称及相对应的值,都必须是字符串类型 - 如果值为 Unicode 字符,需要为字符编码。 - 如果值为二进制数据,则需要使用 BASE64 编码。
属性 | 说明 |
---|---|
domain | 指定了哪些主机可以接受 Cookie。如果不指定,默认为 origin,不包含子域名。如果指定了Domain ,则一般包含子域名。因此,指定 Domain 比省略它的限制要少。 |
path | 指定了主机下的哪些路径可以接受 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符 %x2F (“/“) 作为路径分隔符,子路径也会被匹配。 |
maxAge | cookie 失效的时间,单位秒。如果为整数,则该 cookie 在 maxAge 秒后失效。如果为负数,该 cookie 为临时 cookie ,关闭浏览器即失效,浏览器也不会以任何形式保存该 cookie 。如果为 0,表示删除该 cookie 。默认为 -1。 - 比 expires 好用。 |
expires | 过期时间,在设置的某个时间点后该 cookie 就会失效。 一般浏览器的 cookie 都是默认储存的,当关闭浏览器结束这个会话的时候,这个 cookie 也就会被删除 |
secure | 该 cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。 当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。 |
httpOnly | 如果给某个 cookie 设置了 httpOnly 属性,则无法通过 JS 脚本 读取到该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是在一定程度上可以防止 XSS 攻击,不是绝对的安全 |
在上面提到查看 Cookie 的方式(打开浏览器控制台 -> Application
-> Cookies
),在详情面板可以发现 Cookie 是可编辑的,这就提供了 Cookie 被篡改的可能。另外,很多第三方可以获取到 Cookie,服务器无法判断 Cookie 是不是真实用户发送的,所以可以伪造 Cookie 实现登录进行一些 HTTP 请求。
为了防篡改 Cookie,有两种思路:
思路一:把信息隐藏在服务器中(Session)
思路二:加密(Token)
Session
Session 是另一种记录服务器和客户端会话状态的机制,它是基于 Cookie 实现的,在一次会话中将重要信息保存在 Session 中(Session 存储在服务器端),浏览器只记录 SessionId(一个 SessionId 对应一次会话请求,SessionId 存储在客户端的 Cookie 中)。
Token
Token 的意思是「令牌」,是服务端生成的一串字符串,作为客户端进行请求的一个标识。通常使用 JWT 加密认证。
当用户第一次登录后,服务器生成一个 Token 并将此 Token 返回给客户端,以后客户端只需带上这个 Token 前来请求数据即可,无需再次带上用户名和密码。
区别
Cookie 和 Session 的区别
安全性: Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。
有效期不同: Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
存储大小不同:单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。
Token 和 Session 的区别
状态:Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是访问资源接口(API)时所需要的资源凭证,使服务端无状态化,不会存储会话信息。
扩展性:如果是服务器集群,或者是跨域的服务导向架构,就要求 Session 数据共享,每台服务器都能够读取 Session。由于 Token 是客户端访问时直接带着数据,因此无需做共享数据的操作。
参考文章
一文彻底搞懂Cookie、Session、Token到底是什么