真正“搞”懂HTTP协议09之这个饼干不能吃

我们在之前的文章中介绍HTTP特性的时候聊过,HTTP是无状态的,每次聊起HTTP特性的时候,我都会回忆一下从前辉煌的日子,也就是互联网变革的初期,那时候其实HTTP不需要有状态,就是个浏览页面,没有什么需要记录信息的地方,所以无状态完全符合当时的场景。

另外,无状态也给HTTP带来了不少的好处,正是因为无状态,这样服务器就没有状态差异,就可以很轻易的组成集群,当然,缺点就是无法支持需要记录状态的事务。为了解决这个缺点,Cookie就出现了。

一、这个饼干是什么?

Cookie的核心作用,其实就是让HTTP拥有记忆的能力,虽然服务器记不住,但是服务器可以根据HTTP提供的信息来做出相应的逻辑和判断。你大概可以这样理解,相当于服务器给每一个客户端都贴上了一个小纸条,当服务器把纸条设置好后,会发送给客户端,客户端每次传输HTTP数据的时候,就会把这个小纸条带上发给服务器,服务器就可以见人下菜碟了。

二、小饼干是怎么工作的?

关于Cookie的相关规范,并不在RFC2616或者RFC7230中,而是在RFC6265中,这份规范针对Cookie做了独立、详细的介绍。

Cookie的工作过程主要应用到了两个字段:响应头字段Set-Cookie 和请求头字段Cookie

当客户端像服务器第一次请求资源的时候,服务器会使用Set-Cookie来给客户端贴上一个标签,格式就是"key=value"这样,随着响应报文一起发送给浏览器。这样浏览器在下一次发送请求的时候会自动带上cookie数据,服务器发现欸?这次请求有Cookie,就知道不是首次请求,然后识别Cookie,为该用户提供个性化的服务。

当然,我们还可以使用多个Set-Cookie字段,来设置多个数据,让客户端携带更多的有用的信息。

要注意的是,Cookie与操作系统无关,是浏览器绑定的,当你换了浏览器,实际上相当于一个新的初次请求。

三、Cookie的属性

我们现在知道了,Cookie其实就是服务器委托客户端存储的一些数据,通常这些数据都是用来记录用户的关键信息。那么就需要一些额外的手段来保证Cookie的安全,这些手段就是Cookie的属性。我们下面就来看一下这些常用的有关于Cookie的属性有哪些。

首先,我们可以通过ExpiresMax-Age 设置Cookie的有效期,"Expires "俗称"过期时间",用的是绝对时间点,可以理解为"截止日期"(deadline)。"Max-Age "用的是相对时间,单位是秒,浏览器用收到报文的时间点再加上 Max-Age,就可以得到失效的绝对时间。这两者可以同时出现,两者的失效时间可以一致,也可以不一致,但浏览器会优先采用 Max-Age 计算失效期

其次,我们还可以设置Cookie的作用域,"Domain "和"Path"指定了 Cookie 所属的域名和路径,浏览器在发送 Cookie 前会从 URI 中提取出 host 和 path 部分,对比 Cookie 的属性。如果不满足条件,就不会在请求头里发送 Cookie。

使用这两个属性可以为不同的域名和路径分别设置不同的Cookie,比如/a用一个Cookie,/b用另外一个Cookie,当然通常都是一个"/"就完事了。

最后,我们要考虑的就是Cookie的安全性了,前端的同学们肯定知道,Cookie可以通过document.cookie获取,这样就导致了安全隐患,可能会导致XSS也就是跨站脚本攻击,从而窃取数据。HttpOnly属性就会告诉浏览器,此Cookie只能通过浏览器传输,禁止其它方式的访问,浏览器就会禁止任何API对cookie的访问,从而避免了XSS攻击。

再有,SameSite 属性可以防范"跨站请求伪造"(XSRF)攻击,设置成"SameSite=Strict "可以严格限定 Cookie 不能随着跳转链接跨站发送,而"SameSite=Lax"则略宽松一点,允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。

还有一个属性叫"Secure",表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送。但 Cookie 本身不是加密的,浏览器里还是以明文的形式存在。

四、Cookie的应用场景

其实Cookie最常见的应用场景就是身份识别,保存用户的登录信息,实现会话事务。

另一个常见的场景就是广告追踪,你上网的时候肯定看过很多的广告图片,这些图片背后都是广告商网站(例如 Google),它会"偷偷地"给你贴上 Cookie 小纸条,这样你上其他的网站,别的广告就能用 Cookie 读出你的身份,然后做行为分析,再推给你广告。这种 Cookie 不是由访问的主站存储的,所以又叫"第三方 Cookie"(third-party cookie)。如果广告商势力很大,广告到处都是,那么就比较"恐怖"了,无论你走到哪里它都会通过 Cookie 认出你来,实现广告"精准打击"。为了防止滥用 Cookie 搜集用户隐私,互联网组织相继提出了 DNT(Do Not Track)和 P3P(Platform for Privacy Preferences Project),但实际作用不大

五、例子

我们先来看看简单的Cookie设置。代码也很简单:

arduino 复制代码
res.setHeader("Set-Cookie", ["age=13", "name=zaking"]);

注意,如果你要设置多个Cookie的话,第二个参数要是个数组,我们看下效果:

这是第一次请求,然后我们刷新下页面:

你就能看到请求头中带上了cookie,我们还可以给每个cookie设置它的作用域和失效时间:

arduino 复制代码
res.setHeader("Set-Cookie", [
  "age=13; path=/; max-age=5",
  "name=zaking; path=/set-cookie; max-age=10",
  "hide=true; path=/else; max-age=1000",
]);

记得实验效果之前把上一次的cookie清空噢。然后我们看上面的代码,path限制了路径,所以当我们访问/set-cookie的页面的时候,其实只会有两个cookie,一个有效时间5秒,一个10秒。大家可以自己试下哦:

过了这个时间之后,你会发现一个Cookie都没有了。Cookie的属性中还有一个限制作用域的属性,叫做Domain,这个我就不试了,大家可以自行尝试一下噢。接下来我们看下,我们在页面中通过document.cookie来获取Cookie:

xml 复制代码
<body>
  Cookie
</body>
<script>
  console.log(document.cookie);
</script>

就这么简单,重启服务刷新页面后,可以看到控制台打印出了作用域范围内的Cookie。

我们加个HttpOnly再看看:

arduino 复制代码
res.setHeader("Set-Cookie", [
  "age=13; path=/; max-age=5",
  "name=zaking; path=/set-cookie; max-age=10;HttpOnly",
  "hide=true; path=/else; max-age=1000",
]);

结果就只剩下age了,完全符合我们的预期。

那么例子就到这里啦,还有一些我没写出来噢,比如SameSite和Secure。其实也并不复杂,我就是懒得写了。

六、总结

Cookie其实是有大名的,叫做Magic Cookie,意思是不透明的数据,跟饼干没啥关系噢。早期的Cookie都是存在磁盘上的文本文件,现在基本上是使用数据库存储,比如sqlite,存储的大小有一定的限制,是4k。

如果不指定Cookie生效时间,则会在浏览器关闭后失效,也叫做会话Cookie。历史上还有Set-Cookie2和Cookie2这样的字段,但是现在没用了。

相关推荐
灰子学技术11 小时前
Envoy HTTP 过滤器处理技术文档
网络·网络协议·http
时空自由民.15 小时前
HTTP协议和HTTPS协议结合天气获取案例介绍
网络协议·http·https
时空自由民.21 小时前
HTTP协议帧格式
网络·网络协议·http
Rust研习社1 天前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
灰子学技术1 天前
Envoy HTTP 流量层面的 Metric 指标分析
网络·网络协议·http
TimeAground1 天前
HTTP 协议全解:从报文到 HTTP/3,Android 开发者需要知道的一切
http
lifewange2 天前
如何设计一个 RESTful API
后端·http·restful
夜瞬2 天前
HTTP基础教程:请求方法、状态码、JSON、鉴权、超时、重试与流式返回
网络协议·http·json