Skip to content

Cookie

在程序中,会话跟踪是很重要的事情。
理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,两者不能混淆。
例如,用户 A 在超市购买的任何商品都应该放在 A 的购物车内,不论是用户 A 什么时间购买的,这都是属于同一个会话的,而不能放在用户 B 或者用户 C 的购物车内,这不属于同一个会话。

而 Web 应用程序是使用 HTTP 协议传输数据的。
HTTP 协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接,这就意味着服务器无法从连接上跟踪会话。
即用户 A 购买了一件商品并放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户 A 的会话还是用户 B 的会话了。
要跟踪该会话,必须引入一种机制。Cookie 就是这样的一种机制,它弥补了 HTTP 协议无状态的不足。

Cookie 实际上是一小段的文本信息。
客户端请求服务器,如果服务器需要记录该用户状态,就使用 response 向客户端浏览器方法一个 Cookie。客户端浏览器会把 Cookie 保存起来。
当浏览器再请求该网站时,浏览器把请求的网址连通该 Cookie 一同提交给服务器,服务器检查该 Cookie,以此来辨认用户状态。服务器还可以根据需要修改 Cookie 的内容

很多网站都会使用 Cookie,例如 Google 会向客户端颁发 Cookie,Baidu 也会向客户端颁发 Cookie。
那浏览器访问 Google 会不会也携带上 Baidu 颁发的 Cookie 呢?或者 Google 能不能修改 Baidu 颁发的 Cookie 呢?答案是否定的。Cookie 具有 不可跨域名性
根据 Cookie 规范,浏览器访问 Google 只会携带 Google 的 Cookie,而不会携带 Baidu 的 Cookie;Google 也只能操作 Google 的 Cookie,而不能操作 Baidu 的 Cookie。
Cookie 在客户端是由浏览器来管理的,从而保护用户的隐私安全。浏览器会判断一个网站是否能操作另一个网站 Cookie 的依据是域名,
例如,Google 与 Baidu 的域名不一样,因此 Google 不能操作 Baidu 的 Cookie。
需要注意的是,虽然网站 images.google.com 与网站 www.google.com 同属于 Google,淡水域名不一样,两者同样不能互相操作彼此的 Cookie

如果用户是在自己家的计算机上上网,登录时就可以记住个人的登录信息,下次访问时不需要再次登录,直接访问即可。
实现方法是把登录信息如账号、密码等保存在 Cookie 中,并控制 Cookie 的有效期,下次访问时再验证 Cookie 中的登录信息即可。
保存登录信息有多种方案。最直接的是把用户名与密码都保持到 Cookie 中,下次访问时检查 Cookie 中的用户名与密码,并与数据库比较。
这是一种比较危险的选择,一般不把密码等重要信息保存到 Cookie 中。还有一种方案是把密码加密后保存到 Cookie 中,下次访问时解密并与数据库比较。这种方案略微安全一点。
如果不希望保存密码,还可以把登录的时间戳保存到 Cookie 与数据库中,到时只验证用户名与登录时间戳就可以了。
也可以这样,只在登录时查询一次数据库,以后访问验证登录信息时不再查询数据库。
实现方式是把账号按照一定的规则加密后,连同账号一块保存到 Cookie 中,下次访问时只需要判断账号的加密规则是否正确即可。
最后一种方案,也是现在各大网站的常用做法。

附注: Cookie 指 Web 服务器为了存储某些数据(比如用户信息)而保存在浏览器上的小型文本数据。
浏览器会在一定时间内保存它,并在下一次向同一个服务器发送请求时附带这些数据。
Cookie 通常被用来进行用户会话管理(比如登录状态),保存用户的个性化信息(比如语言偏好,视频上次播放的位置,网站主题选项等)以及记录和收集用户浏览数据以用来分析用户行为等

在 Flask 中,如果想要在响应中添加一个 cookie,最方便的方法是使用 Response 类提供的 set_cookie() 方法。
要使用这个方法,我们需要先使用 make_response() 方法手动生成一个响应对象,传入响应主体作为参数。
这个响应对象默认实例化内置的 Response 类。

set_cookie() 方法支持多个参数来设置 Cookie 的选项,如下表所示

属性 说明
key cookie 的键(名称)
value cookie 的值
max_age cookie 被保存的时间数,单位为秒;默认在用户会话结束(即关闭浏览器)时过期
expires 具体的过期时间,一个 datetime 对象或者 UNIX 时间戳
path 限制 cookie 只在给定的路径可用,默认为整个域名
domain 设置 cookie 可用的域名
secure 设置为 True,只有通过 HTTPS 才可以使用
httponly 如果设为 True,禁止客户端 JavaScript 获取 cookie

当浏览器保存了服务器端设置的 Cookie 后,浏览器再次发送到该服务器的请求会自动携带设置的 Cookie 信息,Cookie 的内容存储在请求首部的 Cookie 字段中

在 Flask 中,Cookie 可以通过请求对象的 cookies 属性读取。

安全问题

由于在 HTTP 请求中的 Cookie 时明文传递的,所以安全性成问题(除非用 HTTPS)

影响性能

一方面,Cookie 包含在每次请求和响应中,太大的 Cookie 会严重影响数据传输,因此哪些数据需要写入 Cookie 需要慎重考虑,尽量减少 Cookie 中传输的数据量。
另一方面,对于某些静态资源的访问,如 CSS,Script 等,发送 Cookie 没有意义,可以考虑静态资源使用独立域名访问,避免请求静态资源时发送 Cookie,减少 Cookie 传输的次数

大小限制

cookie 的大小限制在 4KB 左右,或许在某些情况下有点不够用

对于用户来说,可以通过改变浏览器的设置来禁用 cookie,也可以删除历史的 cookie。
但就目前而言,大多数人都不再禁用 cookie 了

cookie 最让人担心的还是由于它存储了用户的个人信息,并且最终这些信息要发给服务器,那么它就会成为某些人的目标或者工具,比如有 cookie 盗贼,就是搜集用户 cookie,然后利用这些信息进入用户账号,达到个人某种不可告人之目的;
还有被称之为 cookie 投毒的说法,是利用客户端的 cookie 传给服务器的机会,修改传回去的值。
这些行为常常是通过一种被称为 "跨站脚本(Cross site scripting)"(或者跨站指令码)的行为方式实现的。

https://juejin.cn/news/6983616482420719652

https://www.huxiu.com/article/415401.html