Appearance
Cookies
元信息
- 目标:解释"登录状态为何能跨请求保持"——理解 cookie 的读写机制、随 HTTP 头交换的流程、会话失效与同源保护;能分辨 cookie 与 token 两种状态方案的适用场景
- 关键概念:cookie、session_id、Set-Cookie、浏览器会话、Expires、同源策略、token
- 关联阶段:cp3
- 常见误区:以为 cookie 是服务端写进浏览器的数据库(它只是按域名隔离的小文本,客户端也能读写);以为不设过期时间就永久有效(会话 cookie 关浏览器即删);以为换台机器登录状态还在(cookie 不跨设备);以为任何网站的脚本都能读走 cookie(同源策略限定仅同源可读)
前情回顾
- DOM API : 基于js操纵网页(客户端数据)的能力
- 事件 event: 页面交互机制,用户->程序员->浏览器
- Ajax: 基于js发起通讯(服务端数据)的能力
- 回调 callback: 默认的网络事件处理函数,客户端-程序员-->服务端
问题
- 有一些网站,一旦登录,后续再访问该网站,都保持着登录状态。 然而,当你关闭重启浏览器后(或者过一段较长的时间后),就需要你重新登录
- 有一些网站的登录页面,会有一个复选框:记住我一天、一月、一年。当你选中后,即使你关闭浏览器,也不需要重新登录
- 但银行、支付宝比较安全的网站,通常提示:公共场合不要复选它
- 但是,当你换一台机器后,你又需要重新登录
猜想:状态与存储
- 网页一定是在我的电脑里留下什么标记?这些标记并且会定时被清除
- 但是:在浏览器中运行的网页真的能够向我的硬盘里写入数据吗?
- WEB应用为何优于桌面软件,就是因为:安全、安全、安全
什么是 cookies
- 允许浏览器可以读写本地硬盘中一个特殊目录下的特殊文件,即 cookies 文件
- 浏览器默认为每一个域名生成一个cookies文件,并且保证该文件只能被同一域名的页面所读取
使用浏览器的开发者工具(F12)
- application面板:cookies节点中可查看对应域名在本地的存储信息
- network 面板,查看 http 请求的 request和response头信息中的set-cookie和cookie头,可查看其交换机制
cookies的交换机制:服务端发起
- 当Web服务器收到一个客户端请求,要求访问受保护的服务端资源(即需要登录)
- 服务端脚本检查 http request header中是否存在cookies字段,如不存在,则发起一个服务端重定向,指引浏览器转到登录页面
- 用户填写登录表单,即账户信息后,提交给服务端
- 服务端脚本验证账户信息,如成功,则为该账户生成一个随机码作为凭证,一般记为session_id,并保存到服务端的数据库中,如sessions表中。
- 同时,服务端脚本在 http response header中插入一个set cookies字段,其值即为上述的session_id
- 浏览器收到服务端的响应后,会检查 http response header 中是否存在set cookies字段,如有,则将其保存到本地cookies文件或数据库中
- 每当浏览器发起请求时,都会检查目标网站域名是否存在相应的本地cookies数据,如存在,则将其附加在http request header中的cookies字段,发送给服务端
- 服务端脚本收到脚本后,取出cookies的值,并在服务端sessions表中查询,如匹配,则表明该请求来自已登录的用户,同时从sessions表中取出用户名、角色或权限等内容,判定访问权限。
cookies的交换机制:客户端发起
- 客户端也可以创建cookies,即直接修改本地cookies数据
- 在后续的客户端请求中,这些cookies数据仍然通过cookes字段被发送到服务端
客户端创建的cookies通常用于存储临时购物车、收藏夹这类功能,而不用于登录,为什么?
set-cookies 服务端使用 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Reference/Headers/Set-Cookie
cookies 客户端使用 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Reference/Headers/Cookie
cookies的存储位置:现代浏览器
采用文件型数据库,如sqlite,易于管理(chrome://settings/siteData ),但不易查看
- chrome
- C:\Users[username]\AppData\Local\Google\Chrome\User Data\Default\Network
- edge for win10/11
- %LOCALAPPDATA%\Microsoft\Edge\User Data\Default\Network
- firefox
- %APPDATA%\Mozilla\Firefox\Profiles
https://www.thewindowsclub.com/cookies-folder-location-windows
cookies的存储位置:IE浏览器
采用文本文件方式存储,易于观察,但不易于管理
- win10: 浏览器->设置->浏览历史记录->设置->查看文件
- win8:
C:\Users\[账户名]\AppData\Local\Microsoft\Windows\INetCookies - win7
C:\Users\[账户名]\AppData\Roaming\Microsoft\Windows\CookiesC:\Users\[账户名]\AppData\Roaming\Microsoft\Windows\Cookies\Low
- xp
C:\Documents and Settings\[账户名]\Local Settings\cookies\
注意:需要设置显示已隐藏的文件夹 https://www.cnblogs.com/gdyblog/p/5874362.html
参考 https://www.thewindowsclub.com/cookies-folder-location-windows
cookies的结构
- Name: Cookie名称,必须使用只能用在URL中的字符,一般用字母及数字
- Value: Cookie值, 同样也只能使用可以用在URL中的字符,一般需要对其使用encodeURI方法进行转义
- Expires: 过期时间,一个GMT格式的时间
- Path: 路径,在这个路径下面的页面才可以访问该Cookie,一般设为“/”,以表示同一个站点的所有页面都可以访问这个Cookie
- Domain: 子域,指定在该子域下才可以访问Cookie,例如要允许Cookie在 bbs.x.com 下可以访问,但在 www.x.com 下不能访问,则需要将domain设置成bbs.x.com
- Secure: 安全性,指定Cookie是否只能通过https协议访问,一般的Cookie使用HTTP协议既可访问,如果设置了Secure(空值即可),则只有当使用https协议连接时cookie才可以被页面访问
cookies 的读与写
javascript
document.cookie = "userName=" + encodeURI("tom") +
"; expires=" + (new Date("2022-01-01")).toUTCString() +
"; path=/; domain=x.com; secure";
console.log(document.cookie);什么是登录和登出?
- 当用户通过浏览器访问网页时,浏览器将登录信息记录在cookies,并持续发送给服务端脚本
- 当用户不希望浏览器记录自己的访问身份信息时,可禁止浏览器记录(浏览器设置:禁用cookies)或删除掉已存有登录信息的cookies
浏览器会话: cookies的默认失效机制
- 关闭当前登录的浏览器标签窗口,再打开另一个,是否需要重新登录?
- 关闭浏览器的所有窗口标签时,重新打开浏览器,是否需要重新登录?
- cookies的默认设置:如果未对cookies设置失效时间,则在浏览器会话关闭后,浏览器自动删除该cookies
浏览器会话: 浏览器窗口进程的一个生命周期
自定义会话:显示设置失效时间
- 定时登出:登录脚本设置一个有限的未来时间,当时间到达,浏览器将自动删除cookies
- 用户登出: 登录脚本设置一个无限大的未来时间,只有当用户点击登出即执行登出脚本时,登出脚本将设置一个负失效时间(比当前系统时间更早的时间值),浏览器执行脚本时将立即删除该cookies
- 或者浏览器端的cookies被清除(如浏览器重装、系统重装等)
同源: cookies的安全机制
- 在
http://www.a.com登录,用户信息被该站页面的脚本写入cookies。随后,用户又访问了http://www.b.com,请b.com的网页中的脚本是否能读取到含有a.com用户的登录信息? - 如果用户随后访问的是
http://bbs.a.com,请问能否读取到? - 如果用户随后访问的是
https://www.a.com,请问能否读取到?
同源策略: 浏览器的一种安全机制,客户端脚本在没有明确授权的情况下,只能读写与自身同一来源的资源,如cookies等
教程
http://www.runoob.com/js/js-cookies.html
工具
- cookies api 库,简化和统一cookie的读写 https://github.com/js-cookie/js-cookie
- 开源的Cookie管理器(Chrome 扩展)https://github.com/Dolov/chrome-best-cookier
扩展阅读:token
另一种保持状态的机制:客户端发起的每一个请求,即所有的链接和表单中,都需要附带一个参数,形如:
但上述方式的处理较为不便,需要服务端脚本成生成页面时,对每一个链接和表单进行处理。
另一种方式是将状态变量(即上述的user_id)保存在http数据包的字段中,类似于cookies的交换和传输:
- 当登录验证通过后,服务端脚本在http响应包中插入一个自定义的字段,比如x-token
- 客户端脚本在收到http响应包后,将其暂存在本地存储中(见后),当发起下一个http请求时,则将该字段的值,附加到http请求包中,发给服务端
- 服务端脚本收到客户端请求时,如果从http请求包中检测到x-token字段,并且其值有效(在已登录的用户列表中存在相同的值),则表明该请求是登录过的用户发来的,从而给予相应权限。
Token vs Cookies
- Cookies 是浏览器默认支持的状态交换协议,且包含了存储的功能。优点是方便,但受到协议的限制。适合于轻客户端+重服务端的应用,如服务端驱动的应用。
- Token 则是开发者自行定义的状态交换协议,且不与存储功能绑定。优点是易于扩展,缺点则是需要开发者提供实现机制,如前端、后端脚本的同步传输和存储。适合于重js或重客户端的应用,如单页SPA应用。
more
- cookies 和 tokens https://tommihovi.com/2024/05/demystifying-cookies-and-tokens/
- Session、JWT、Token、SSO、OAuth 2.0 认证逻辑 https://mp.weixin.qq.com/s/kiz7ZkXH_-tO-agmUh30YA