0x01:Cookie 简介
Cookie,它的名字源于一种叫 Fortune Cookie 的饼干(又叫 “幸运签饼”),该饼干是一个新月形的薄脆饼干,里面包裹着寓意祝福或预言的签文小纸条,如下图所示:
在计算机网络中,Cookie 是一种由服务器发送到客户端(通常是浏览器)并保存在客户端的一串文本字符串。它通常保存了用户的一些敏感信息(如用户身份 ID、用户偏好设置等)。当用户重新访问服务器时,浏览器会将客户端的 Cookie 重新发送回服务器,从而让服务器识别用户或者恢复用户之前的会话状态。
0x02:Cookie 的诞生原因及其特点
0x0201:Cookie 的诞生原因
Cookie 的出现主要是为了解决HTTP 协议无状态的问题,并满足 WEB 发展过程中的新需求。
HTTP(超文本传输协议)是一种无状态的协议,意味着每个请求都是独立的,服务器无法直接识别出连续请求是否来自同一个用户。整个流程就如下图所示:
小明想要办理话费充值业务,就需要提供自己的姓名。但是当你告诉服务器你的姓名后,它只在那一轮对话中知道你是你,对话结束后,它就给你忘了(渣机)。当你想要重新办理话费充值业务的时候,它又要你提供姓名了。没办法,陷入了死局。
上面的图只是举例,实际客户端咋可能就是小明嘞,服务器要同时处理成千上万个人的请求,你一言我一语,服务器哪知道哪句话是谁讲的嘞。
这种无状态性在 WEB 发展初期并没有太大的问题,因为早期的网页大多是静态的,用户浏览网页只是简单地获取页面内容,不需要服务器记住用户的身份或状态(你可以理解为,早期互联网主打一个信息共享,我发布了信息,谁看,我不在乎,不像现在,还分 VIP 啥的)。
但是随着 WEB 技术的发展,网站开始提供更加丰富和个性化的服务,如会员机制、购物车、用户偏好设置等。这些服务要求服务器能够识别出用户的身份和状态,以便在用户再次访问时能够提供相应的服务。然而,HTTP 协议的无状态性使得服务器无法直接做到这一点。
为了解决 HTTP 协议无状态性的问题,人们开始探索各种解决方案。最初,有人提出通过用户的 IP 地址来跟踪用户的身份,但这种方式存在一个明显的问题,因为 IP 地址对应的是机器而非用户,且一太机器可能供多个用户使用。
为了更准确地跟踪用户的身份和状态,Cookie 技术应运而生。Cookie 是一种由服务器发送到客户端(通常是浏览器)并保存在客户端的文本字符串。每当用户访问网站时,浏览器都会将 Cookie 发送给服务器,服务器通过解析 Cookie 中的信息来识别用户,从而提供个性化的服务。(说人话,就是,每次请求的时候都带上“我是谁”,比如:“我是小明,我要办理话费充值业务。”)
所以现在的请求流程就变成了下面这样:
在第一轮请求的时候,你告诉了服务器“你是谁”。服务器就会将“你是谁”的信息,存储在一个叫 Cookie 的字段中,并发送给你,接下来你每次发起请求,浏览器就会将 Cookie 中的内容一起发送给服务器,这样,服务器就知道你是谁,你有什么喜好,你做过哪些操作啦(烦人的个性化广告)。
0x0202:Cookie 的特点
下面是 Cookie 的一些主要特点:
-
存储在客户端: Cookie 数据存储在用户的浏览器上,而不是服务器上。这意味着每次用户访问网站时,浏览器都会将 Cookie 发送到服务器,服务器则可以根据这些信息来识别用户或维护用户会话。
-
明文存储: Cookie 中的信息是以明文形式存储在客户端的。这意味着任何人都可以通过访问用户的计算机或使用网络抓包工具来查看 Cookie 的内容。因此,Cookie 中不应该包含敏感信息,如密码、信用卡号等。
-
用户可编辑: 用户可以通过浏览器的设置来管理 Cookie,包括查看、删除或禁用 Cookie。这为用户提供了一定的隐私保护和控制权。
-
有大小限制: 单个 Cookie 的大小通常有限制,大多数浏览器支持的最大 Cookie 大小为 4096 字节,即 4KB。这限制了单个 Cookie 可以存储的数据量。如果需要存储更多数据,可以考虑使用多个 Cookie 或使用其他存储机制(如 LocalStorage)。
-
自动发送: 每当用户访问创建该 Cookie 的服务器(或该服务器下的资源)时,浏览器都会自动将 Cookie 发送到服务器。这使得服务器能够识别用户并跟踪用户的会话状态。
-
有效期: Cookie 可以设置有效期(通过
Expires
或Max-Age
属性)。如果设置了有效期,Cookie 将在指定的时间后过期,并在过期后被浏览器删除。如果未设置有效期,Cookie 将成为会话 Cookie,它将在浏览器关闭时自动删除。 -
安全性: 虽然 Cookie 存储在客户端,但它们可以通过设置
HttpOnly
和Secure
属性来提高安全性。HttpOnly
属性可以防止客户端脚本(如 JavaScript)访问 Cookie,从而减少跨站脚本攻击(XSS)的风险。Secure
属性则要求 Cookie 仅通过 HTTPS 连接发送,增加数据传输的安全性。 -
路径和域限制: Cookie 可以被限制在特定的路径或域下。这意味着只有访问指定路径或域下的资源时,Cookie 才会被发送。这有助于减少不必要的 Cookie 传输,提高隐私保护。
-
跨域问题: 默认情况下,出于安全性考虑,Cookie 是不能跨域访问的。即,一个域下的 Cookie 不会被发送到另一个域的服务器上。但是,可以通过设置
Domain
属性来允许子域之间的 Cookie 共享。
0x03:Cookie 从创建到销毁的全流程
接下来,我们通过一个实验来大致了解一下 Cookie 的生命周期,即从创建 Cookie 到销毁 Cookie,Cookie 在我们的通信过程中到底扮演了一个什么样的角色。
本部分主要是辅助理解 Cookie 在通信过程中的作用,并不要求一定要重复实验。当然,为了方便一些感兴趣的小伙伴,所以这里也附上了实验环境的搭建流程。
0x0301:实验环境搭建
附件资源
PHP 运行环境:phpstudy_x64_8.1.1.3.zip
Cookie 实验源码包:CookieLab01.zip
1. 下载 PhpStudy 并启用 Apache 服务
将适合 Windows 版本的 PhpStudy 安装包下载至本地,并且完成解压:
双击进入解压后的文件夹中,可以看到下面的内容:
双击 PhpStudy 安装包,即可进入安装页面,在这里,我们需要设置 PhpStudy 的安装目录,并且确保目录中不存在中文或空格(这里笔者选择安装在 C:\phpstudy_pro
目录下,因为是虚拟机中,如果是实体机的话,笔者建议安装在 C 盘以外的其他盘符中):
配置完成后,点击 “立即安装” 即可,然后就是耐心等待安装程序完成安装:
安装完成后,桌面会出现一个 phpstudy_pro
的程序快捷键,双击快捷键即可启动程序,启动完成后界面如下,至此 PhpStudy 已安装完毕:
在后面的实验中我们需要访问本地的 WEB 站点,所以还需要开启 Apache 服务,开启后的界面如下:
2. 导入 CookieLab 源码包并访问实验环境
安装完 PhpStudy 之后,就可以将 CookieLab 的源码包导入到站点中了。
将 CookieLab 源码包下载至本地并完成解压:
下面我们要将解压后的文件夹,放到站点根目录下。PhpStudy 中定位站点根目录的方法如下:
打开站点根目录后,直接将 CookieLab 源码包拖进去即可:
源码包导入成功后,就可以访问实验环境了(确保 PhpStudy Apache 服务开启):
http://127.0.0.1/CookieLab01
0x0302:实验流程记录
进入实验环境,右击页面,打开 “开发者工具”,切换到 “存储” 模块中,该模块存储了当前站点的 Cookie,可以看到是啥都没有的(笔者实验采用的是 FireFox 浏览器):
1. Cookie 的创建
接下来,在登录框中随便输入一个用户名和密码,点击登录:
可以看到,当我们点击登录后,向后端发起了一个请求,在该请求包的响应包中,服务器通过 Set-Cookie
字段为我们的客户端设置了 Cookie,同时,界面也变成了 HI,Blue17
,证明了页面认识我们了。
如果此时再次查看 “存储” 信息,你会看到这么一条数据:
这条数据,就是服务端为我们创建的 Cookie 信息,该数据就保存在客户端上,并且可以通过浏览器查看(感兴趣的小伙伴还可以手动修改值,刷新一下,看看页面还会发生什么变化)。
2. Cookie 的使用
我们新开一个页面,重新访问该站点,可以看到,页面依旧是认识我们的:
这就是由于,我们在新打开的页面中访问实验站点的时候,携带上了第一次请求中服务端给我们设置的 Cookie。打开“开发者工具”,刷新页面,在 “网络” 标签下进行抓包:
可以看到,当我们再次访问当前站点时,浏览器自动为我们的请求包中添加上了 Cookie 字段,并将该字段发送给了服务器。服务器也成功接收了 Cookie 字段的内容,并认为我们依旧处于登录状态。
这就是 Cookie 的主要用途,跟踪用户的会话状态。
3. Cookie 的销毁
点击页面上的 “Destruction Of Account”,注销账户:
可以看到,本地存储的 Cookie 内容就消失了,如果此时新开一个页面重新访问,你会发现,依旧是未登录的状态:
销毁 Cookie 的内容,在后端的代码里,是这么写的:
setcookie("Username", "", time() - 60);
其实就是将 Cookie 中 Username
字段的过期时间,设置为一分钟前(让这条信息过期即可)。
0x04:Set-Cookie 的各部分组成
在之前的 Cookie 实验中,我们发现了,服务器是通过响应包中的 Set-Cookie
字段来为客户端设置 Cookie 的。不同的后端语言,对应了不同的语法来设置 Cookie,但是总的来说,Set-Cookie
是由以下三个部分组成的:前缀、键值对、属性。
所以,我们在响应包中看到的 Set-Cookie
应该多以下面的格式展示:
<!--
<cookie-prefix>: 前缀[可选]
<cookie-name>=<cookie-value>: 键值对(必须); 例如: Username=Blue17
expires=<date>; Secure; HttpOnly : 这些都是属性
-->
Set-Cookie: <cookie-prefix><cookie-name>=<cookie-value>; expires=<date>; Secure; HttpOnly
下面是一个实际的例子(带有前缀的):
<!--
_Secure- : 前缀
Username=Blue17 : 键值对
expires=Tue, 03-Sep-2024 06:04:41 GMT; path=/CookieLab01; domain=example.com; secure; httponly: 这些全部都是描述该条 Cookie 的属性
-->
Set-Cookie:__Secure-Username=Blue17; expires=Tue, 03-Sep-2024 06:04:41 GMT; path=/CookieLab01; domain=example.com; secure; httponly
接下来我们详细的讲解以下,各部分的作用以及语法说明。
0x0401:Cookie 的前缀
Cookie 的前缀是一种在 Cookie 的名称中携带信息的方式(如上面的例子,就是在键值对的 Key 前增加特定的前缀),它必须和某些属性同时出现,否则 Cookie 无法设置成功。
Cookie 的前缀主要有以下两种:
前缀 | 说明 |
---|---|
__Secure- | 告诉浏览器需要设置 Secure 属性 |
__Host- | 告诉浏览器需要设置 Path=/ 和 Secure 属性,同时不应当设置 Domain 属性 |
下面是一些实际的例子,可以在客户端手动测试:
// 支持 Cookie 前缀的收到下面设置的时候会拒绝,因为没有同时设置 Secure 属性
document.cookie = "__Secure-Username=Blue17";
// 这样设置才能成功!
document.cookie = "__Secure-Username=Blue17; Secure";
// 当响应来自于一个安全域(HTTPS)的时候,二者都可以被客户端接受
Set-Cookie: __Secure-ID=123; Secure; Domain=example.com
Set-Cookie: __Host-ID=123; Secure; Path=/
// 缺少 Secure 属性,会被拒绝
Set-Cookie: __Secure-id=1
// 缺少 Path=/ ,会被拒绝
Set-Cookie: __Host-id=1; Secure
那么,现在摆出一个问题,这些前缀出现的原因是什么呢?我有了 Secure
属性,干嘛还要给我的 Cookie 加上特定的 __Secure-
前缀呢?
原因很简单,那就是 Secure
属性是可以被移除的,但是如果你移除了 Cookie 名称的前缀,相当于更改了 Cookie 的键了,后端压根就不接收你新创建的 Cookie。
下面这个例子,可能会辅助你的理解:
我们先通过浏览器自带的开发者工具,为测试站点添加一个带有 Secure
属性的 Cookie:
document.cookie = "Username=Blue17; Secure"
这个时候切换到 “存储” 模块,可以看到,其 Secure
属性被设置为 true
:
这个时候,我们去控制台,重写一个 Cookie ,覆盖它的 Secure
属性:
document.cookie = "Username=Blue17"
再次查看 “存储” 模块,可以看到,Secure
属性,被很轻易的在客户端覆盖了。
如果给我们的 Cookie 加上前缀呢?浏览器在设置 Cookie 的时候就会自动做一遍校验:
倘若攻击者想要去掉前缀,抱歉,我后端接收的就是带前缀的,你去掉前缀就是一个新 Cookie 了,我后端不认。
以上就是 Cookie 前缀的作用。
0x0402:Cookie 键值对
<cookie-name>=<cookie-value>
Cookie 的键值对,是 Cookie 中真正携带信息的部分,例如:
Username=Blue17
<cookie-name>
是 Cookie 的键,或者说是该 Cookie 的名称,它是一个字符串,用于唯一标识 Cookie 中的某个特定数据项。键是区分大小写的,这意味着 Username
和 username
,会被视为两个不同的键。键的选择应该具有描述性,以便于理解其存储的数据内容。
<cookie-name>
的组成可以是除了控制字符(CTLs)、空格(spaces)或制表符(tab)之外的任何 US-ASCII 字符。同时不能包含以下特殊符号: ()<>@,;:\"/[]?={}
。
<cookie-value>
是 Cookie 的值,值是与键相关联的数据,它同样是一个字符串。该项为非必填项目,如果有值,那么需要包含在双引号里面。支持除了控制字符(CTLs)、空格(spaces)、双引号(double quotes)、逗号(comma)、分号(semicolon)以及反斜线(backslash)之外的任意 US-ASCII 字符。
0x0403:Cookie 的属性
Cookie 的属性可以理解为 Cookie 的配置项,告诉浏览器 Cookie 的一些额外信息,比如什么时候使用该 Cookie,该 Cookie 什么时候失效等等。下面是一份 Cookie 属性的速查表:
属性名 | 简介 | 类型 | 默认值 | 示例 |
---|---|---|---|---|
Domain | 生效域名 | String | 当前访问地址中的 host 部分 | blue17.vip |
Path | 生效路径 | String | / | /docs |
Expires | 过期时间 | Date | 浏览器会话关闭时间 | Thu, 22 Jul 2021 00:53:13 GMT |
Max-Age | 有效期,单位为(秒) | Number | 1000 | |
Secure | 仅 HTTPS 可用 | 无值,出现即设置 | ||
HttpOnly | 设置了 HttpOnly 属性的 Cookie 不能通过 JavaScript 进行访问 | 无值,出现即设置 | ||
SameSite | 允许服务器设定 Cookie 不随着跨站请求一起发送 | String | Lax | 值可能为: Lax Strict None |
SameParty | 允许特定条件跨域共享 Cookie | 无值,出现即设置 | ||
Priority | 优先级,仅 Chrome 支持 | Medium | 值可能为: Low Medium High |
接下来,我们将详细讲解一下 Cookie 各个属性的作用。
1. Domain - 生效域名设置
Domain
属性指定了哪些域名下的请求可以携带该 Cookie,比如下面这个例子:
Set-Cookie: Username=Blue17; Domain=blue17.vip
表示只要是发送给 blue17.vip 这个站点下(包括其子站点,例如 www.blue17.vip
)的请求,都会携带上该 Cookie。
如果不设置,默认为 origin
,不包含子域名;如果指定了 Domain
,则一般包含子域名,就和上面一样。
当前大多数浏览器遵循 RFC 6265,设置
Domain
时 不需要加前导点。如果浏览器不遵循该规范,则需要加前导点,例如:Domain=.blue17.vip
2. Path - 生效路径设置
Path
属性指定了目标站点的哪些路径可以接收该 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符 %x2F
(“/
”)作为路径分隔符,子路径也会被匹配。
例如,设置 Path=/docs
,则以下地址都会被匹配:
-
/docs
-
/docs/Web/
-
/docs/Web/HTTP
3. Expires - 过期时间设置
Expires
属性用于设置 Cookie 的过期时间,可以传递一个符合 HTTP-Date 格式的值,例如: expires=Mon, 14 Mar 2022 15:39:34 GMT;
如果不设置 Expires
属性,则 Cookie 将成为会话 Cookie,它将在浏览器关闭时自动删除。
4. Max-Age - 有效期设置(秒)
Max-Age
属性用于设置 Cookie 失效前需要经过的秒数。秒数为 0 或 -1 将会使 Cookie 直接过期。一些老的浏览器(IE 6、IE 7 和 IE 8)不支持这个属性。
如果 Expires
属性和 Max-Age
属性同时存在,Max-Age
优先级更高。
5. Secure - 仅 HTTPS 可用
标记为 Secure
的 Cookie 只有当客户端通过 HTTPS 协议对服务器发起请求时,才会被携带着一起发送给服务器。这可以预防 man-in-the-middle 攻击。
但即便是设置了 Secure
标记,敏感信息也不应该通过 Cookie 来进行传输,因为 Cookie 固有的不安全性,Secure
标记也无法为其提供确实的安全保障。例如:可以查看用户的浏览器,以获取 Cookie(Cookie 是明文存放的)。
6. HttpOnly - 不允许 JavaScript 访问
设置了 HttpOnly
属性的 Cookie 不允许通过 JavaScript 脚本去更改这个值,该值在 document.cookie
中同样也不可见:
7. SameSite - 设置 Cookie 不随跨站请求一起发送
SameSite
属性用于设置某个 Cookie 在跨站请求时不会被发送,从而阻止 CSRF(跨站请求伪造攻击)。
SameSite
属性可以有下面三种值:
-
None
:浏览器会在同站请求、跨站请求下继续发送 Cookies,不区分大小写。 -
Strict
:浏览器只在访问站点与 Cookie 生效的域相同时发送 Cookie。 -
Lax
:新版本默认设置为 Lax。与Strict
类似,但是在特定条件下也可以发送跨域请求:-
URL 必须发生变化
-
HTTP 请求方式必须是安全的,例如
GET
、HEAD
、OPTIONS
,它们不改变数据。
-
举例来说,设置了 SameSite=Lax
属性的 Cookie,当用户从 a.com 跳转到 b.com(除了跳转,还有图片加载、iframe 调用等也符合条件),URL 发生了变化的同时请求方式为 GET,则该 Cookie 会被发送过去。
拓展: SameSite 与 Domain 的区别:
上面提到过,Domain
可以指定 Cookie 生效的域名,那 SameSite
和 Domain
的区别在哪里呢?
简而言之,就是 Domain
限制了接收 Cookie 的域名,而 SameSite
则限制了发送 Cookie
的域名。
举例来说:
Set-Cookie: Username=Blue17; Path=/; Secure; Domain=blue17.vip;
上面这条 Cookie,只要请求的目标是 blue17.vip
或者其子站点 blog.blue17.vip
,该 Cookie 都会被携带上,发送给服务器。
Set-Cookie: Username=Blue17; Path=/; Secure; Domain=blue17.vip; SameSite=strict;
而上面这个 Cookie,只有当请求是从 blue17.vip
这个站点发起的,才会被携带。
8. SameParty - 允许特定条件跨域共享 Cookie
SameParty
属性用于配合 First-Party Sets
实现跨域共享属性,详情查看:详解 Cookie 新增的 SameParty 属性。
9. Priority - (Chrome)Cookie 优先级设置
该属性目前只在 Chrome 中受到支持:draft-west-cookie-priority-00
Cookie 是有数量限制的,所以当 Cookie 超过一定数量时,浏览器默认会清除最早过期的 Cookie。
如果设置了 Priority,Chrome 会先将优先级低的清除,并且每种优先级的 Cookie 至少会保留一个。该属性可以有下面三种值:
-
Low
:低优先级 -
Medium
:默认值,中等优先级 -
High
:高优先级
0x05:客户端如何操作 Cookie
这部分的内容就是简单讲解一下如何在客户端通过 JavaScript 脚本来对 Cookie 进行操作。
0x0501:基础知识
在接下来的实验中,我们会使用以下几条语句来完成对 Cookie 的增删改查:
获取 Cookie: document.cookie;
设置 Cookie: document.cookie="<cookie-name>=<cookie-value>";
修改 Cookie: document.cookie="<cookie-name>=<new-cookie-value>";
删除 Cookie: document.cookie="<cookie-name>=<cookie-value>; expires=Thu, 01 Jan 1970 00:00:01 GMT;" // 删除 Cookie 就是使 Cookie 过期
0x0502:实验流程
打开 FireFox 火狐浏览器,访问测试站点:
http://127.0.0.1/CookieLab01/index.php
鼠标右击页面,选择 ”检查“,打开 ”开发者工具“:
选择 ”控制台(Concole)“ 模块,输入以下代码,可以查看当前站点的 Cookie:
document.cookie // 查看当前站点的 Cookie
输入下面的内容,可以为当前站点添加 Cookie:
document.cookie="Username=Blue17";
可以看到,我们已经成功把 Username
写入到了本机的 Cookie 中,选择 ”网络(Network)“,刷新页面,查看响应包:
可以看到,当我们再次请求该站点时,已经把我们在客户端添加的 Cookie 带上了。
回到 “控制台” 菜单,输入下面的代码,修改我们添加的 Cookie:
document.cookie="Username=Blue18";
刷新页面,可以看到,我们修改后的 Cookie 也被成功发送到了服务端:
接下来,输入下面的代码,将删除本地键为 Username
的 Cookie:
document.cookie="Username=''; expires=Thu, 01 Jan 1970 00:00:01 GMT;"
0x06:关于 Cookie 的安全漏洞
0x0601:XSS — 跨站脚本攻击
参考资料:XSS 漏洞 - 学习手册
跨站脚本(Cross-Site Scripting,简称为 XSS)是一种针对网站应用程序的安全漏洞攻击技术,是代码注入的一种。它允许用户将恶意代码注入网页,当其他用户在浏览网页时就会受到影响。恶意用户利用 XSS 代码攻击成功后,可能得到很高的权限(如执行一些操作)、私密网页内容、会话和 Cookie 等各种内容。
想象一下,当 Hacker 将恶意的 JavaScript 脚本放到了你访问的站点上,当你重新访问时,脚本执行,将你的 Cookie 直接传给 Hacker,你的账号不就无了嘛。
0x0602:CSRF — 跨站请求伪造攻击
CSRF(Cross-site request forgery,跨站请求伪造)也被成为 One Click Attack 或者 Session Riding,通常缩写为 CSRF 或者 XSRF,是一种针对网站的恶意利用。简单来说,就是攻击者通过一些技术手段,伪造用户的身份(通过 Cookie)访问用户曾经去过的一个站点并进行一些操作。
假设,一家银行用来转账操作的 URL 如下:
http://www.bank.com/transfer?amount=1000&for=TargetAccount
amount
后跟的是转账金额,for
后跟的是转账的账户。
那么 Hacker 可能会在某个站点中放置下面的代码(<img>
是图片标签):
<img src="http://www.bank.com/transfer?amount=1000&for=1234567890">
那么当用户访问站点的时候,由于 img
标签自动加载图片,就会向银行转账的 URL 发起请求,恰巧,用户刚刚访问过银行页面,登录信息(Cookie)尚未过期。导致发起请求后,银行后端以为是用户正常操作,于是将用户账户中的 1000 元,就转向了目标账户。
通过设置 sameSite
可以防止跨域发送 Cookie,抵御 CSRF 攻击。
0x07:关于 Cookie 的随笔杂记
0x0701:Cookie 保存在哪里?
通过简介,我们知道 Cookie 是一组存放在客户端的数据,那么这个数据存放在哪里呢?
不同浏览器保存 Cookie 的位置不同,下面附上 Google 浏览器本地 Cookie 的保存路径:
C:\Users\<电脑的用户名>\AppData\Local\Google\Chrome\User Data\Default\Network
可以看到我本地的 Cookie 已经到 1312KB 了,比一般小文件还是大不少的。
Cookies 文件会以某种方式进行编码,所以在本地我们无法直接通过记事本等软件打开查看其内容。
0x08:参考资料
Cookie 前缀如何让 Cookie 更安全?-阿里云开发者社区Cookie 前缀如何让 Cookie 更安全?https://developer.aliyun.com/article/116668
标签:浏览器,Secure,用户,详解,Cookie,服务器,属性,客户端 From: https://blog.csdn.net/m0_73360524/article/details/141869063