一、引入 Cookie
定义
HTTP Cookie(也称为 Web Cookie、 浏览器 Cookie 或简称 Cookie,中文意思为 "曲奇饼,小甜饼") 是服务器发送到用户浏览器并保存在浏览器上的一小块数据, 它会在浏览器之后向同一服务器再次发起请求时被携带并发送到服务器上。
通常, 它用于告知服务端两个请求是否来自同一浏览器, 如保持用户的登录状态、 记录用户偏好等。
- cookie的可以记录用户的ID,记录用户的密码,记录用户浏览过的商品记录。
- 但是无法记录用户的浏览器设置(浏览器设置属于浏览器,而并不属于某次请求的信息)
工作原理
- 当用户第一次访问网站时, 服务器会在响应的 HTTP 头中设置 Set-Cookie字段, 用于发送 Cookie 到用户的浏览器。
- 浏览器在接收到 Cookie 后, 会将其保存在本地(通常是按照域名进行存储) 。
在之后的请求中, 浏览器会 自动在 HTTP 请求头 中携带 Cookie
字段, 将之前保存的 Cookie 信息发送给服务器。
分类
- 会话 Cookie( Session Cookie) : 在浏览器关闭时失效。
- 持久 Cookie( Persistent Cookie) : 带有明确的过期日期或持续时间,可以跨多个浏览器会话存在。
如果 cookie 是一个持久性的 cookie, 那么它其实就是浏览器相关的, 特定目录下的一个文件。 但直接查看这些文件可能会看到乱码或无法读取的内容,因为 cookie 文件通常以二进制或 sqlite 格式存储。 一般我们查看, 直接在浏览器对应的选项中直接查看即可。
如下:

安全性
- 由于 Cookie 是存储在客户端的, 因此存在被篡改或窃取的风险
用途
服务器将 Cookie 返回给浏览器, 客户端(浏览器)这边就会通过 Cookie 保存当前用户的状态,当客户端访问服务器时,就会自动把 Cookie 内容带入到请求中,服务器接收到之后,就能知道当前客户是谁,现在客户端处于什么状态了,当前客户的服务提供到哪个环节了。Cookie 就像是 服务器在客户端搞的一个寄存处一样。
- 用户认证和会话管理(最重要)
- 跟踪用户行为
- 缓存用户偏好等
- 比如在 chrome 浏览器下, 可以直接访问: chrome://settings/cookies
二、认识 Cookie
Cookie 就是浏览器给页面提供的一种能持久化存储数据的机制。
- 浏览器为了安全默认是不让网页访问用户电脑上的文件系统, 但是有时确实需要让页面存储一些数据,方便后续访问网站。
- 于是浏览器不让页面访问整个磁盘数据,但是单独给页面分配了一块空间,有多种不同的形式, Cookie 是最经典的形式
- HTTP 存在一个报头选项: Set-Cookie, 可以用来进行给浏览器设置
Cookie值
- 在 HTTP 响应头中添加, 客户端(如浏览器) 获取并自行设置并保存
Cookie
Cookie的格式及组成
Set-Cookie: <name>=<value>
其中 <name> 是 Cookie 的名称, <value> 是 Cookie 的值。
完整格式如下:
Set-Cookie: username=peter; expires=Thu, 18 Dec 2024 12:00:00 UTC; path=/; domain=.example.com; secure; HttpOnly
Cookie 组成
- Key(名称)
- Value (值) : 根据 Key 可以获取对应的 value.
- Domain(域名): 指定可以访问 Cookie 的域名。通常情况下,Cookie 只能被设置在创建它的域名以及其子域名下。上图中我们访问的是 抖音, 那么 Cookie 的 Domain 就是 douyin.com。
- Path(路径): 指定可以访问 Cookie 的路径。这个字段定义了在哪些路径下的请求可以发送 Cookie。上图中 Path 为 "/", 说明只要是 douyin.com 这个域名, 不管访问的是抖音 的哪个路径下的资源, 都可以在请求中使用浏览器中存储的 Cookie。
- Expires(过期时间): 一旦过了这个时间,浏览器将不再发送该 Cookie。如果未设置 Expires 字段,Cookie 将被视为会话 Cookie,它会在用户关闭浏览器时自动删除。
- 大小: 指定了 Cookie 的大小,单位为字节。
- HttpOnly: 布尔值字段,设置为 true,那么该 Cookie 只能通过 HTTP 或 HTTPS 协议访问,不能通过 JavaScript 或其他客户端脚本访问。有助于增强安全性,以防止恶意脚本访问敏感信息。
- Secure: 布尔值字段,设置为 true,那么该 Cookie 只能在通过 HTTPS 等安全连接发送时才会被浏览器发送到服务器。有助于保护敏感信息的传输安全。SameSite: 限制第三方cookie,表示Cookie不随着跨域请求发送,减少安全风险。它可以有三个可能的值:Strict、Lax、None。
- Strict 表示只有在同一站点的请求中才会发送 Cookie;Lax 在某些情况下允许 Cookie 在跨站点请求中发送(例如从外部链接打开的页面);None 允许 Cookie 在任何情况下都发送。SameSite 设置有助于减少跨站点请求伪造(CSRF)攻击和提高隐私。
- Partition Key(分区键): 一个标识符,指示 Cookie 属于哪个上下文或分区。它通常用于在浏览器中隔离不同网站或应用程序的 Cookie 数据,以增强隐私和安全性。每个不同的域名下都可以有不同的 Cookie, 不同网站之间的 Cookie 并不冲突.
- Priority(优先级): 指定了 Cookie 的传输优先级。Cookie数量超出限制时低优先级会被优先清除.
Cookie 的组织形式
- 先按照域名进行组织, 针对每个域名, 分别分配一块空间.
- 一块空间里又会按照键值对的方式组织数据.
国际时间 UTC
时间格式必须遵守 RFC 1123 标准, 具体格式样例: Tue, 01 Jan 2030 12:34:56 GMT
或者 UTC(推荐)。
关于时间解释
- Tue: 星期二(星期几的缩写)
- ,: 逗号分隔符
- 01:日期(两位数表示)
- Jan:一月(月份的缩写)
- 2030:年份(四位数)
- 12:34:56:时间(小时、 分钟、 秒)
- GMT:格林威治标准时间(时区缩写)
GMT(格林威治标准时间) VS UTC(协调世界时)
两者是两个不同的时间标准, 但它们在大多数情况下非常接近, 常常被混淆。 以下是两者的简单解释和区别:
- GMT(格林威治标准时间) :
GMT 是格林威治标准时间的缩写, 它是以英国伦敦的格林威治区为基准的世界-时间标准。
GMT 不受夏令时或其他因素的影响, 通常用于航海、 航空、 科学、 天文等领域。
GMT 的计算方式是基于地球的自转和公转。
UTC(协调世界时) :
UTC 全称为"协调世界时", 是国际电信联盟(ITU)制定和维护的标准时间。
UTC 的计算方式是基于原子钟, 而不是地球的自转, 因此它比 GMT 更准确。 据称, 世界上最精确的原子钟 50 亿年才会误差 1 秒。
UTC 是现在用的时间标准, 多数全球性的网络和软件系统将其作为标准时间。
区别:
- 计算方式: GMT 基于地球的自转和公转, 而 UTC 基于原子钟。
- 准确度: 由于 UTC 基于原子钟, 它比基于地球自转的 GMT 更加精确。
在实际使用中, GMT 和 UTC 之间的差别通常很小, 大多数情况下可以互换使用。 但在需要高精度时间计量的场合, 如科学研究、 网络通信等, UTC 是更为准确的选择。
std::string GetMonthName(int month)
{
std::vector<std::string> months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
return months[month];
}
std::string GetWeekDayName(int day)
{
std::vector<std::string> weekdays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
return weekdays[day];
}
std::string ExpireTimeUseRfc1123(int t) // 秒级别的未来UTC时间
{
time_t timeout = time(nullptr) + t;
struct tm *tm = gmtime(&timeout); // 这里不能用localtime,因为localtime是默认带了时区的. gmtime获取的就是UTC统一时间
char timebuffer[1024];
//时间格式如: expires=Thu, 18 Dec 2024 12:00:00 UTC
snprintf(timebuffer, sizeof(timebuffer), "%s, %02d %s %d %02d:%02d:%02d UTC",
GetWeekDayName(tm->tm_wday).c_str(),
tm->tm_mday,
GetMonthName(tm->tm_mon).c_str(),
tm->tm_year+1900,
tm->tm_hour,
tm->tm_min,
tm->tm_sec
);
return timebuffer;
}

Cookie 安全性
单独使用 Cookie, 有什么问题?
- 我们写入的是测试数据, 如果写入的是用户的私密数据呢? 比如, 用户名密码,浏览痕迹等。
- 本质问题在于这些用户私密数据在浏览器(用户端)保存, 非常容易被人盗取, 更重要的是, 除了被盗取, 还有就是用户私密数据也就泄漏了。
如何提高 Cookie 的安全性?
对保存到 cookie 里面的敏感信息加密
HttpOnly 设为 true,那么该 Cookie 将只能通过 HTTP 或 HTTPS 协议访问,而不能通过 JavaScript 或其他客户端脚本访问, 防止其他恶意脚本访问 Cookie 盗取信息.
Secure 设为 true,只通过 HTTPS 等安全连接发送时才会被浏览器发送到服务器, 防止其他恶意网站窃取 Cookie 信息.
设置 Cookie 过期时间.
expires:指定了coolie的生存期,默认情况下cookie是暂时存在的,他们存储的值只在浏览器会话期间存在,当用户退出浏览器后这些值也会丢失,如果想让cookie存在一段时间,就要为expires属性设置为未来的一个过期日期。现在已经被max-age属性所取代,max-age用秒来设置cookie的生存期
设置指定的访问域名
domain:可以访问该Cookie的域名。如果设置为".google.com",则所有以"google.com"结尾的域名都可以访问该Cookie。注意第一个字符必须为"."。
path:Cookie的使用路径。如果设置为"/sessionWeb/",则只有contextPath为"/sessionWeb"的程序可以访问该Cookie。如果设置为"/",则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为"/"。
给 Cookie 设置 IP 戳和 时间 戳, 设置 Cookie 在同个 IP 下多长时间失效.
注意: 上面这些设置都是服务器设置的,因为 Cookie 本身就是 服务器返回给浏览器,浏览器只是简单的进行了存储.
其他 -- 补充
🧑💻 关于其他可选属性的解释

注意事项
- 每个 Cookie 属性都以分号(;) 和空格( ) 分隔。
- 名称和值之间使用等号(=) 分隔。
- 如果 Cookie 的名称或值包含特殊字符(如空格、 分号、 逗号等) , 则需要进行 URL 编码。
Cookie有哪些缺陷 ?
-
数量受到限制。一个浏览器能创建的 Cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的
Cookie 总数不能超过 20 个 -
安全性无法得到保障。通常跨站点脚本攻击往往利用网站漏洞在网站页面中植入脚本代码或网站页面引用第三方法脚本代码,均存在跨站点脚本攻击的可能,在受到跨站点脚本攻击时,脚本指令将会读取当前站点的所有Cookie 内容(已不存在 Cookie 作用域限制),然后通过某种方式将 Cookie 内容提交到指定的服务器(如:AJAX)。一旦 Cookie 落入攻击者手中,它将会重现其价值。
-
浏览器可以禁用Cookie,禁用Cookie后,也就无法享有Cookie带来的方便
Cookie 的生命周期
- 如果设置了
expires
属性, 则 Cookie 将在指定的日期/时间后过期。 - 如果没有设置
expires
属性, 则 Cookie 默认为会话Cookie
, 即当浏览器关闭时过期。

Session
基本概念
HTTP Session
是服务器用来跟踪用户与服务器交互期间用户状态的机制。 由于 HTTP 协议是无状态的(每个请求都是独立的) , 因此服务器需要通过 Session 来记住用户的信息。
- 一般session的有效期默认是30分钟
"无状态" 的含义指的是:
- 默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系.
- 但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.
- 例如登陆网站成功后, 第二次访问的时候服务器就能知道该请求是否是已经登陆过了。

上面的令牌通常就是服务器以 Cookie 形式返回给浏览器, 服务器存储的用户信息对应的就是 Session。通常情况下,一个用户关联一个 Session (会话)。
打个比方:去医院看病.
到了医院先挂号. 挂号时需提供身份证, 同时得到了一张 "就诊卡", 这个就诊卡就相当于患者的 "令牌". 同时医院的系统中会记录用户的看病信息。
后续去各个科室进行检查, 诊断, 开药等操作, 都不必再出示身份证了, 只要凭就诊卡即可识别出当前患者的身份,知道患者的病史。
看完病了之后, 不想要就诊卡了, 就可以注销这个卡. 此时患者的身份和就诊卡的关联就销毁了. (类似于网站的注销操作)
又来看病, 可以办一张新的就诊卡, 此时就得到了一个新的 "令牌"。
就诊卡就是 Cookie, 但是 Cookie 存储的数据是有限的,且易丢失,关键信息都存储在服务器上,以 会话(Session)的形式。
服务器这边就需要记录令牌信息, 以及令牌对应的用户信息, 这个就是 Session
机制所做的工作.
2. 工作原理 -- 会话机制
服务器同一时刻收到的请求是很多的. 服务器需要清除的区分清楚每个请求是从属于哪个用户, 就需要在服务器这边记录每个用户令牌以及用户的信息的对应关系.
在上面的例子中, 就诊卡就是一张 "令牌". 要想让这个令牌能够生效, 就需要医院这边通过系统记录每个就诊卡和患者信息之间的关联关系.
会话的本质就是一个 "哈希表", 存储了一些键值对结构. key 就是令牌的 ID(token/sessionId), value 就是用户信息(用户信息可以根据需求灵活设计).
session ID
是由服务器生成的一个 "唯一性字符串", 又叫 token

- 当用户首次访问网站时, 服务器会为用户创建一个唯一的
Session ID
, 并通过 Cookie 将其发送到客户端 (例如通过 HTTP 响应中的 Set-Cookie 字段返回)。 - 客户端在之后的请求中会携带这个
Session ID
, 服务器通过Session ID
来识别用户, 从而获取用户的会话信息。 - 服务器通常会将 Session 信息存储在内存、 数据库或缓存中。
如果重启服务器则 Session 数据就会丢失,用户注销 Session 也会丢失, 同时Session
也有过期时间。(Session 的默认过期时间30分钟)
其他 -- 补充
安全性:
与 Cookie 相似, 由于 Session ID 是在客户端和服务器之间传递的, 因此也存在被窃取的风险。
但是一般虽然 Cookie 被盗取了, 但是用户只泄漏了一个 Session ID, 私密信息暂时没有被泄露的风险
Session ID 便于服务端进行客户端有效性的管理, 比如异地登录。
可以通过 HTTPS 和设置合适的 Cookie 属性(如 HttpOnly 和 Secure) 来增强安全性
超时和失效:
- Session 可以设置超时时间, 当超过这个时间后, Session 会自动失效。
- 服务器也可以主动使 Session 失效, 例如当用户登出时。
用途:
- 用户认证和会话管理
- 存储用户的临时数据(如购物车内容)
- 实现分布式系统的会话共享(通过将会话数据存储在共享数据库或缓存中)
Cookie 和 Session 的联系与区别
联系:在网站的登录功能中,Cookie 与 Session 一般需要配合使用
web开发发展至今,cookie和session的使用已经出现了一些非常成熟的方案。在如今的市场或者企业里,一般有两种存储方式:
存储在服务端:通过 cookie
存储一个 session_id
,然后具体的数据则是保存在session
中。如果用户已经登录,则服务器会在 cookie
中保存一个 session_id
,下次再次请求的时候,会把该 session_id
携带上来,服务器根据 session_id
在 session
库中获取用户的 session
数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做 server side session
。
将 session
数据加密,然后存储在 cookie
中。这种专业术语叫做 client side session
。flask采用的就是这种方式,但是也可以替换成其他形式。
区别:
-
Cookie 是客户端的机制. Session 是服务器端的机制.
-
Cookie 里面可以存储各种键值对(还可以存储别的),Session 专门用来保存用户的身份信息。
-
Cookie 和 Session 经常会在一起配合使用. 但是不是必须配合.完全可以用 Cookie 来保存一些数据在客户端. 这些数据不一定是用户身份信息, 也不一定是token / session ID.
-
Session 中的 token / session ID 也不需要非得通过 Cookie / Set-Cookie 传递.比如使用 手机 APP 进行登录,服务器里面还需要 Session, 但是就没有 Cookie 这个概念。也就是说 Cookie 是与 浏览器强相关的
-
安全与性能问题
cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,但是cookie存在一定的缺陷:比如有大小限制,单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie
所以:将登陆信息等重要信息存放为 session
;其他信息如果需要保留,可以放在cookie
中