HTTP Cookie深入解析:Web会话追踪的秘密

HTTP Cookie深入解析:Web会话追踪的秘密

🍑个人主页:Jupiter.🚀 所属专栏:Linux从入门到进阶欢迎大家点赞收藏评论😊

在这里插入图片描述
在这里插入图片描述

目录


当我们登录了B站过后,为什么下次访问B站就不需要登陆了?

  • 问题:B 站是如何认识我这个登录用户的?
  • 问题:HTTP 是无状态,无连接的,怎么能够记住我?

定义

HTTP Cookie(也称为 Web Cookie、浏览器 Cookie 或简称 Cookie)是服务器发送到用户浏览器并保存在浏览器上的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态、记录用户偏好等。

工作原理

  • 当用户第一次访问网站时,服务器会在响应的 HTTP 头中设置 Set-Cookie字段(如Set-Cookie : user = zhangsan),用于发送 Cookie 到用户的浏览器。
  • 浏览器在接收到 Cookie 后,会将其保存在本地(通常是按照域名进行存储)。
  • 在之后的请求中,浏览器会自动在 HTTP 请求头中携带 Cookie 字段,将之前保存的 Cookie 信息发送给服务器。

分类

  • 会话 Cookie(Session Cookie):在浏览器关闭时失效。
  • 持久 Cookie(Persistent Cookie):带有明确的过期日期或持续时间,可以跨多个浏览器会话存在。
  • 如果 cookie 是一个持久性的 cookie,那么它其实就是浏览器相关的,特定目录下的一个文件。但直接查看这些文件可能会看到乱码或无法读取的内容,因为 cookie 文件通常以二进制或 sqlite 格式存储。一般我们查看,直接在浏览器对应的选项中直接查看即可。
  • 类似于下面这种方式:

安全性

  • 由于 Cookie 是存储在客户端的,因此存在被篡改或窃取的风险。

用途

  • 用户认证和会话管理(最重要)
  • 跟踪用户行为
  • 缓存用户偏好等
  • 比如在 chrome 浏览器下,可以直接访问:link
  • HTTP 存在一个报头选项:Set-Cookie, 可以用来进行给浏览器设置 Cookie值。
  • HTTP 响应报头中添加,客户端(如浏览器)获取并自行设置并保存Cookie。

服务器发送Cookie

  • 当客户端(如浏览器)首次请求服务器资源时,服务器可能会在HTTP响应中包含一个或多个Set-Cookie头部。这些Set-Cookie头部指示客户端存储特定的信息(即Cookie)。
  • 每个Set-Cookie头部都包含了Cookie的名称、值以及可选的属性,如过期时间(Expires/Max-Age)、作用域(Path)、安全性要求(Secure)、跨站策略(SameSite)以及是否只能通过HTTP接口访问(HttpOnly)等。

客户端接收并保存Cookie

  • 浏览器接收到包含Set-Cookie头部的HTTP响应后,会解析这些头部,并根据其中的指令将Cookie存储到本地。
  • 存储的Cookie会包含名称、值以及所有相关的属性。
  • 浏览器会根据Cookie的过期时间和其他属性来决定何时删除这些Cookie。

客户端发送Cookie

  • 当浏览器再次向同一服务器(或符合Cookie作用域的其他服务器)发送请求时,它会自动检查是否有与该请求相关的Cookie。如果有,浏览器会将这些Cookie附加到HTTP请求的Cookie头部,并发送给服务器。服务器接收到请求后,可以从Cookie头部中读取这些Cookie,并根据需要处理它们。

基本格式

在这里插入图片描述


完整的 Set-Cookie 示例

在这里插入图片描述


时间格式必须遵守 RFC 1123 标准,具体格式样例:Tue, 01 Jan 2030 12:34:56 GMT 或者 UTC(推荐)。
关于时间解释

  • Tue: 星期二(星期几的缩写)
  • , : 逗号分隔符
  • 18: 日期(两位数表示)
  • Thu: 月份的缩写
  • 2024: 年份(四位数)
  • 12:34:56: 时间(小时、分钟、秒)
  • GMT: 格林威治标准时间(时区缩写)

GMT 和 UTC 都曾是或现在是国际上重要的时间标准,但由于地球自转的不规则性和原子钟的精确性,UTC 已经成为了全球性的标准时间,而 GMT 则更多被用作历史和地理上的参考。

关于其他可选属性的解释

  • expires=<date>:设置 Cookie 的过期日期/时间。如果未指定此属性,则 Cookie 默认为会话 Cookie,即当浏览器关闭时过期。
  • path=<some_path>:限制 Cookie 发送到服务器的哪些路径。默认为设置它的路径。
  • domain=<domain_name>:指定哪些主机可以接受该 Cookie。默认为设置它的主机。
  • secure:仅当使用 HTTPS 协议时才发送 Cookie。这有助于防止Cookie 在不安全的 HTTP 连接中被截获。
  • HttpOnly:标记 Cookie 为 HttpOnly,意味着该 Cookie 不能被客户端脚本(如 JavaScript)访问。这有助于防止跨站脚本攻击(XSS)。

以下是对 Set-Cookie 头部字段的简洁介绍

注意事项

  • 每个 Cookie 属性都以分号(;)和空格( )分隔。
  • 名称和值之间使用等号(=)分隔。
  • 如果 Cookie 的名称或值包含特殊字符(如空格、分号、逗号等),则需要进行 URL 编码。

Cookie 的生命周期

  • 如果设置了 expires 属性,则 Cookie 将在指定的日期/时间后过期。
  • 如果没有设置 expires 属性,则 Cookie 默认为会话 Cookie,即当浏览器关闭时过期。

安全性考虑

  • 使用 secure 标志可以确保 Cookie 仅在 HTTPS 连接上发送,从而提高安全性。
  • 使用 HttpOnly 标志可以防止客户端脚本(如 JavaScript)访问 Cookie,从而防止 XSS 攻击。
  • 通过合理设置 Set-Cookie 的格式和属性,可以确保 Cookie 的安全性、有效性和可访问性,从而满足 Web 应用程序的需求。

测试 cookie 的关键性完整代码全部附在最后。

  • 测试 cookie 写入到浏览器
 resp.AddHeader("Set-Cookie: username=zhangsan;");//响应中添加一行报头即可
  • 测试自动提交
  • 测试写入过期时间
    • 这里要由我们自己形成 UTC 统一标准时间:
//时间格式如: expires=Thu, 18 Dec 2024 12:00:00 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;structtm*tm =gmtime(&timeout);// 这里不能用localtime,因为localtime是默认带了时区的. gmtime获取的就是UTC统一时间char timebuffer[1024];//时间格式如: expires=Thu, 18 Dec 2024 12:00:00 UTCsnprintf(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;}
在这里插入图片描述
  • 测试路径 path

提交到非/a/b 路径下

  • 比如:http://8.137.19.140:8888/a/x
  • 比如:http://8.137.19.140:8888/
  • 比如:http://8.137.19.140:8888/x/y
在这里插入图片描述


单独使用 Cookie,有什么问题?

  • 我们写入的是测试数据,如果写入的是用户的私密数据呢?比如,用户名密码,浏览痕迹等。
  • 本质问题在于这些用户私密数据在浏览器(用户端)保存,非常容易被人盗取,更重要的是,除了被盗取,还有就是用户私密数据也就泄漏了。

Cookie测试代码

#pragmaonce#include<iostream>#include<string>#include<sstream>#include<vector>#include<memory>#include<ctime>#include"TcpServer.hpp"const std::string HttpSep ="\r\n";// 可以配置的const std::string homepage ="index.html";const std::string wwwroot ="./wwwroot";classHttpRequest{public:HttpRequest():_req_blank(HttpSep),_path(wwwroot){}boolGetLine(std::string &str, std::string *line){auto pos = str.find(HttpSep);if(pos == std::string::npos)returnfalse;*line = str.substr(0, pos);// \r\n str.erase(0, pos + HttpSep.size());returntrue;}boolDeserialize(std::string &request){ std::string line;bool ok =GetLine(request,&line);if(!ok)returnfalse; _req_line = line;while(true){bool ok =GetLine(request,&line);if(ok && line.empty()){ _req_content = request;break;}elseif(ok &&!line.empty()){ _req_header.push_back(line);}else{break;}}returntrue;}~HttpRequest(){}private:// http报文自动 std::string _req_line;// method url http_version std::vector<std::string> _req_header; std::string _req_blank; std::string _req_content;// 解析之后的内容 std::string _method; std::string _url;// /dira/dirb/x.html /dira/dirb/XX?usrname=100&&password=1234 /dira/dirb std::string _http_version; std::string _path;// "./wwwroot" std::string _suffix;// 请求资源的后缀};const std::string BlankSep =" ";const std::string LineSep ="\r\n";classHttpResponse{public:HttpResponse():_http_version("HTTP/1.0"),_status_code(200),_status_code_desc("OK"),_resp_blank(LineSep){}voidSetCode(int code){ _status_code = code;}voidSetDesc(const std::string &desc){ _status_code_desc = desc;}voidMakeStatusLine(){ _status_line = _http_version + BlankSep + std::to_string(_status_code)+ BlankSep + _status_code_desc + LineSep;}voidAddHeader(const std::string &header){ _resp_header.push_back(header+LineSep);}voidAddContent(const std::string &content){ _resp_content = content;} std::string Serialize(){MakeStatusLine(); std::string response_str = _status_line;for(auto&header : _resp_header){ response_str += header;} response_str += _resp_blank; response_str += _resp_content;return response_str;}~HttpResponse(){}private: std::string _status_line; std::vector<std::string> _resp_header; std::string _resp_blank; std::string _resp_content;// body// httpversion StatusCode StatusCodeDesc std::string _http_version;int _status_code; std::string _status_code_desc;};classHttp{private: 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;structtm*tm =gmtime(&timeout);// 这里不能用localtime,因为localtime是默认带了时区的. gmtime获取的就是UTC统一时间char timebuffer[1024];//时间格式如: expires=Thu, 18 Dec 2024 12:00:00 UTCsnprintf(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;}public:Http(uint16_t port){ _tsvr = std::make_unique<TcpServer>(port, std::bind(&Http::HandlerHttp,this, std::placeholders::_1)); _tsvr->Init();} std::string ProveCookieWrite()// 证明cookie能被写入浏览器{return"Set-Cookie: username=zhangsan;";}// resp.AddHeader(ProveCookieWrite()); //测试cookie被写入与自动提交 std::string ProveCookieTimeOut(){return"Set-Cookie: username=zhangsan; expires="+ExpireTimeUseRfc1123(60)+";";// 让cookie 1min后过期} std::string ProvePath(){return"Set-Cookie: username=zhangsan; path=/a/b;";} std::string ProveOtherCookie(){return"Set-Cookie: passwd=1234567890; path=/a/b;";} std::string HandlerHttp(std::string request){ HttpRequest req; req.Deserialize(request); req.DebugHttp(); lg.LogMessage(Debug,"%s\n",ExpireTimeUseRfc1123(60).c_str()); HttpResponse resp; resp.SetCode(200); resp.SetDesc("OK"); resp.AddHeader("Content-Type: text/html");// resp.AddHeader(ProveCookieWrite()); //测试cookie被写入与自动提交// resp.AddHeader(ProveCookieTimeOut()); //测试过期时间的写入// resp.AddHeader(ProvePath()); // 测试路径 resp.AddHeader(ProvePath()); resp.AddHeader(ProveOtherCookie()); resp.AddContent("<html><h1>helloworld</h1></html>");return resp.Serialize();}voidRun(){ _tsvr->Start();}~Http(){}private: std::unique_ptr<TcpServer> _tsvr;};

Read more

即插即用系列 | 2024 SOTA LAM-YOLO : 无人机小目标检测模型

即插即用系列 | 2024 SOTA LAM-YOLO : 无人机小目标检测模型

论文名称:LAM-YOLO: Drones-based Small Object Detection on Lighting-Occlusion Attention Mechanism YOLO 论文原文 (Paper):https://arxiv.org/abs/2411.00485 GitHub 仓库链接:https://github.com/AITricks/AITricks 哔哩哔哩视频讲解:https://space.bilibili.com/57394501?spm_id_from=333.337.0.0 目录 * 1. 核心思想 * 2. 背景与动机 * 3. 主要贡献点 * 4. 方法细节 * 5. 即插即用模块的作用

智能家居联动全攻略:新手如何实现多品牌设备统一控制与家庭自动化

智能家居联动全攻略:新手如何实现多品牌设备统一控制与家庭自动化 【免费下载链接】haier 项目地址: https://gitcode.com/gh_mirrors/ha/haier 每天醒来打开手机,你是否需要在3个不同的APP间切换才能开启空调、热水器和智能灯?出门前是不是总要反复检查每个设备是否关闭?这些智能家居的"碎片化"体验,正在让本应便捷的生活变得更加复杂。今天我将为你展示如何通过开源集成方案,把所有智能设备统一管理起来,真正实现"一个APP控制全屋"的智能家居体验。 🧩 智能家居集成:从设备混战到统一指挥 想象一下这样的生活场景:下班回家走到门口,门锁自动识别身份,屋内灯光渐次亮起,空调已提前调节到26℃舒适温度,热水器完成预热随时可以使用——这不是科幻电影,而是通过智能家居集成就能实现的日常。 为什么需要智能家居集成? * 打破品牌壁垒:让小米、海尔、华为等不同品牌设备协同工作 * 简化操作流程:告别在多个APP间切换的繁琐 * 实现复杂场景:创建"

复杂三维山地环境下小龙虾优化算法COA求解多无人机动态避障路径规划研究附MATLAB代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 🍎 往期回顾关注个人主页:Matlab科研工作室  👇 关注我领取海量matlab电子书和数学建模资料  🍊个人信条:格物致知,完整Matlab代码获取及仿真咨询内容私信。 🔥 内容介绍 一、引言 随着无人机技术的快速发展,多无人机协同作业在复杂环境中的应用越来越广泛,如地质勘探、森林防火、应急救援等领域。复杂三维山地环境给无人机路径规划带来了巨大挑战,需要在考虑地形复杂、障碍物众多且可能动态变化的情况下,为多架无人机规划安全、高效的飞行路径。小龙虾优化算法(COA)作为一种新兴的智能优化算法,为解决这一难题提供了新的思路。 二、复杂三维山地环境下多无人机路径规划的挑战 (一)地形复杂性 1. 三维地形建模困难:山地环境具有复杂的三维地形,包括山峰、山谷、悬崖等。准确地对这种地形进行建模需要大量的地理信息数据,并且如何将这些数据转化为适合路径规划算法处理的模型是一个难题。传统的二维地图难以描述山地的垂直信息,而

探析仓储机器人行业商业模式升级:解决方案服务的价值变现路径

本文将对仓储机器人行业的商业模式升级进行探讨,特别是聚焦于解决方案服务在其中的关键地位。当前,行业正朝向自动化、灵活性增强和服务多样化的方向发展,企业需要建设以客户为中心的服务体验。这一转型不仅提升了客户满意度,还为企业创造了新的收入来源。通过深入分析成功案例,我们发现,创新的解决方案能够有效满足不断变化的客户需求,提高运营效率。此外,数据驱动决策与个性化服务相结合,使企业更具竞争力并推动行业朝向可持续增长迈进。围绕这些主题展开讨论,将有助于更全面地理解仓储机器人行业未来的发展潜力与挑战。 仓储机器人行业的当前发展趋势 近年来,仓储机器人行业不断向前发展,呈现出多元化和高效化的趋势。随着电商的发展,企业对仓储效率的要求日益增加,仓储机器人逐渐成为提升运营效率的重要工具。根据中网B2B战略咨询数据,越来越多企业将营销战略与仓储机器人结合,通过战略升级实现品牌升维。此外,权威机构指出,解决方案服务正成为价值变现的有效路径,各大企业也在积极探索创新商业模式,以满足不断变化的客户需求。以下是当前的一些主要发展趋势: 发展趋势 描述 自动化水平提升 机器人技术的进步使得仓库管理