你真的了解 Cookie 和 Session 吗?

news2025/1/16 13:54:03

文章目录

  • Cookie 和 Session
  • 总结

Cookie 和 Session

cookie

HTTP cookie(web cookie、browser cookie)是服务器发送给用户 web 浏览器的一小段数据。浏览器可能会存储 cookie,并在以后的请求中将其发送回同一台服务器。通常,HTTP cookie 用于判断两个请求是否来自同一个浏览器 - 例如,保持用户登录。它为无状态 HTTP 协议记住有状态信息。

cookie 主要用于三个目的:

  • 会话管理:登录、购物车、游戏分数或其它服务器需要保存的数据。
  • 个性化:用户首选项、主体和其它设置。
  • 跟踪:记录和分析用户行为。

示例:当你登录一次哔哩哔哩软件时,使用完成之后关闭掉该网站,下次开启电脑再次访问该网站时,你的账号依然是已经登录的状态。这实际上就是使用 cookie 实现的,如下所示,点击浏览器地址栏左侧的锁标志,你就可以看到对于网站的各种 cookie 数据了。

在这里插入图片描述

用户在通过身份验证并且服务器成功设置了 cookie 之后,服务器会将该 cookie 作为 HTTP 响应的一部分发送给浏览器。浏览器收到响应后会自动解析 cookie 的值,并将其保存在浏览器的 cookie 存储中。这样,用户的身份信息就会以加密的形式是保存在浏览器的 cookie 文件中。

当用户在之后的请i去中访问同一网站时,浏览器会自动将响应的 cookie 信息加到请求中的 cookie 标头中,并发送给服务器。服务器可以通过这些 cookie 信息来识别用户并提供个性化的服务,例如保持用户的登录状态。

在这里插入图片描述

浏览器会自动管理 cookie 的生命周期和安全性。如果你删除该网站对应的 cookie 信息,那么下次再访问时,就需要重新进行账号登录了。

注意:要查看存储的 cookie(以及网页可以使用的其它存储),你可以开启开发人员哦工具中的存储检测器并从存储树中选择 cookie。

cookie 被盗取

如果你存储在浏览器中的 cookie 信息被未经授权的用户盗取,那么该用户就可以使用你的 cookie 信息以你的身份来访问你之前访问过的网站。(例如:QQ被盗,身份泄密等)这种情况都称为 cookie 被盗取。

恶意链接是一种常见的网络攻击方式,黑客可以通过欺骗用户点击恶意链接来窃取其Cookie。以下是一个示例:假设您收到一封看似来自银行的电子邮件,邮件内容称您的账户存在异常,需要您点击链接以确认身份。然而,该链接实际上是一个恶意链接,当您点击时,黑客将会收到您的 Cookie 信息。一旦黑客获取了您的 Cookie,他们可以使用它来伪装成您,访问您的账户,进行各种恶意活动,如盗取个人信息、进行非法转账等。

什么是 Session

  • Session 代表了服务器和客户端之间的一次会话过程。在 Web 应用程序中,当用户与服务器建立会话时,服务器会为该用户创建一个唯一的 Session 对象。该 Session 对象用于存储特定用户会话所需的属性和配置信息。
  • 在整个用户会话中,当用户在应用程序的不同 Web 页面之间跳转时,存储在 Session 对象中的变量和数据不会丢失,而是持续存在。这使得应用程序能够跟踪和管理用户的状态和数据,以提供个性化的服务和功能。
  • 当客户端关闭会话(例如关闭浏览器)或者 Session 超时失效时,会话结束,Session 对象中的数据也随之销毁。会话超时时间通常由应用程序的配置决定,以平衡用户体验和服务器资源的利用。
  • 通过使用 Session,应用程序可以在用户会话期间保持持久性数据,并确保用户的状态和信息不会再页面跳转或重新加载时丢失。这对于实现登录认证、购物车功能、个性化设置都非常有用。

Cookie 和 Session 之间有什么不同?

  • 存储位置:Cookie 保存在客户端(浏览器)中,而 Session 保存在服务器端。
  • 存储内容:Cookie 只能保存 ASCII 字符,而 Session 可以存储任意数据类。通常情况下,我们可以在 Session 中保存一些常用的变量信息,如用户ID 等。
  • 有效期:Cookie 可以设置长时间保持,比如经常使用的默认登录功能。Session 的有效时间相对较短,通常在客户端关闭或 Session 超时后会失效。
  • 隐私策略:由于 Cookie 存储在客户端,相对容易收到非法获取的风险。在早期,有些网站将个人信息存储在 Cookie 中,导致信息被盗取。而 Session 数据存储在服务器中,相对来说安全性更高。
  • 存储大小:单个 Cookie 的存储容量有限,一般不超过 4KB。而 Session 可以存储的数据量远远超过 Cookie 的限制,因为它存储在服务器的内存或数据库中。

为什么需要 cookie 和 session 配合使用,它们之间的关联。

为什么需要使用 Cookie,这就要从浏览器说起,我们知道浏览器是没有状态的(HTTP 协议无状态),这意味着浏览器无法记住用户信息,这时就需要使用一个机制来告诉服务器,本次操作用户是否登录以及是哪一个用户等。而仅仅使用 Cookie 来存储用户数据存在安全风险,一旦 Cookie 文件泄漏,用户的隐私数据也会泄漏。因此,为了增加安全性,那这套机制的实现就需要 Cookie 和 Session 的配合。

在这里插入图片描述

在用户首次请求服务器时,服务器会根据用户提交的相关信息生成一个对应的 Session,并将 Session 的唯一标识信息(SessionID)返回给浏览器,浏览器收到 SessionID 之后,会将其存储在 Cookie 中并记录此 SessionID 属于哪个域名。

当用户再次访问服务器时,浏览器会自动判断此域名是否存在 Cookie 信息,并在请求中自动发送 Cookie 信息给服务器。服务器会从 Cookie 中获取 SessionID,并根据 SessionID 查找对应的 Session 信息。如果没有找到 Session,说明用户没有登录或登录失效;如果找到了 Session,就标识用户已登录,服务器可以根据 Session 中的信息执行后续的操作。

无论使用哪一种方案,安全都是相对的。

安全是相对的,没有绝对的安全性。无论是使用账号密码直接发送到网络中,还是使用 SessionID 进行身份认证,都存在一定的风险。即使使用加密等安全措施,也无法完全消除所有的潜在威胁。

安全性评估通常会考虑破解成本与收益之间的关系。如果破解某个信息的成本非常高,远远大于攻击获取信息带来的收益,那么这个信息就是相对安全的。因此,在设计安全系统时,我们尽量提高攻击者获取有价值信息的成本,以增加安全性。

对于使用 Session 的方式,尽管 SessionID 可能会被盗取,但相比直接在每次请求中发送账号和密码信息,它降低了账号密码被泄漏的风险。

HTTP 响应中设置 Cookie 字段

当浏览器访问服务器时,若服务器给浏览器的 HTTP 响应中包含 Set-Cookie 字段,那么浏览器再次访问该服务器时就会携带上该 Cookie 字段。

如下所示,当浏览器访问服务器时,我们给响应的报头中添加上一个 Set-Cookie 字段,测试当浏览器第二次访问该服务器时会不会携带上该 Cookie 字段。

#define CRLF "\r\n"
#define SPACE " "
#define SPACE_LEN strlen(SPACE)
#define HOME_PAGE "index.html"
#define ROOT_PATH "wwwroot"

string getPath(string http_request)
{
    size_t pos = http_request.find(CRLF);
    if (pos == string::npos)
        return "";
    string request_line = http_request.substr(0, pos);
    // GET /a/b/c http/1.1
    size_t first = request_line.find(SPACE);
    if (first == string::npos)
        return "";
    size_t second = request_line.rfind(SPACE);
    if (second == string::npos)
        return "";

    string path = request_line.substr(first + SPACE_LEN, second - (first + SPACE_LEN));
    if (path.size() == 1 && path[0] == '/')
        path += HOME_PAGE;

    return path;
}

string readFile(const string &recource)
{
    ifstream in(recource, std::ifstream::binary);

    if (!in.is_open())
        return "404";
    string content;
    string line;
    while (getline(in, line))
        content += line;
    in.close();

    return content;
}

void handlerHttpRequest(int sock)
{
    cout << "---------------------------------------------------" << endl;
    char buffer[10240];
    ssize_t s = read(sock, buffer, sizeof buffer);
    if (s > 0)
        cout << buffer;

    string path = getPath(buffer);
    std::string recource = ROOT_PATH;
    recource += path;

    string html = readFile(recource);
    size_t pos = recource.rfind(".");
    string suffix = recource.substr(pos);
  
    // 开始响应
    std::string response;
    response = "HTTP/1.0 200 OK\r\n";
    if (suffix == ".jpg")
        response += "Content-Type: image/jpeg\r\n";
    else
        response += "Content-Type: text/html\r\n";
    response += ("Content-Length: " + to_string(html.size()) + "\r\n");
    response += "Set-Cookie: This is my cookie content;\r\n";
    response += "\r\n";
    response += html;

    send(sock, response.c_str(), response.size(), 0);
}

class ServerTcp
{
public:
    ServerTcp(uint16_t port, const std::string &ip = "")
        : port_(port), ip_(ip), listenSock_(-1)
    {
        quit_ = false;
    }

    ~ServerTcp()
    {
        if (listenSock_ >= 0)
            close(listenSock_);
    }

public:
    void init()
    {
        // 1. 创建socket
        listenSock_ = socket(PF_INET, SOCK_STREAM, 0);
        if (listenSock_ < 0)
        {
            exit(1);
        }

        // 2. bind
        // 2.1 填充服务器信息
        struct sockaddr_in local; // 用户栈
        memset(&local, 0, sizeof local);
        local.sin_family = PF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        // 2.2 本地socket信息,写入sock_对应的内核区域
        if (bind(listenSock_, (const struct sockaddr *)&local, sizeof local) < 0)
        {
            exit(2);
        }

        // 3. 监听socket,为何要监听呢?tcp是面向连接的!
        if (listen(listenSock_, 5) < 0)
        {
            exit(3);
        }
    }

    void loop()
    {
        signal(SIGCHLD, SIG_IGN);
        while (!quit_)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // 4. 获取连接,accept的返回值是一个新的socket fd
            int serviceSock = accept(listenSock_, (struct sockaddr *)&peer, &len);
            if (quit_)
                break;
            if (serviceSock < 0)
            {
                cerr << "accept error..." << endl;
                // 获取连接失败,继续获取
                continue;
            }
            // 4.1 获取客户端基本信息
            uint16_t peerPort = ntohs(peer.sin_port);
            std::string peerIp = inet_ntoa(peer.sin_addr);
            
            pid_t id = fork();
            assert(id != -1);
            if (id == 0)
            {
                close(listenSock_); // 建议
                if (fork() > 0)
                    exit(0);
                handlerHttpRequest(serviceSock);
                exit(0);
            }
            close(serviceSock);
            wait();
        }
    }

    bool quitServer()
    {
        quit_ = true;
        return true;
    }

private:
    int listenSock_;
    uint16_t port_;
    std::string ip_;
    bool quit_; // 安全退出
};

运行服务器并使用浏览器访问,此时我们通过 Fiddler 可以看到服务器给浏览器的 HTTP 响应报头中共包含了 Set-Cookie 字段。

在这里插入图片描述

总结

Cookie 和 Session 是 Web 开发中常用的数据存储和传递技术。Cookie 将数据存储在客户端浏览器,通过 HTTP 请求自动发送给服务器;而 Session 将数据信息存储在服务器中,通过 Cookie 或 URL 重写将 SessionID 发送给客户端。它们存储位置、数据容量、安全性、传输方式、生命周期和应用场景等方面都具有明显差异。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1233246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库中的undo与redo的作用

undo与redo的作用 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定期…

Git - 版本控制系统

一、概述 git是一个免费开源&#xff0c;分布式的代码版本控制系统&#xff0c;帮助开发团队维护代码。作用是记录代码内容&#xff0c;切换代码版本&#xff0c;多人开发时高效合并代码内容。 直接安装git&#xff0c;默认下一步&#xff0c;然后就能在VScode中看到git控制台 …

YOLOv8更换骨干网络HorNet:递归门控卷积的高效高阶空间交互——涨点神器!

🗝️YOLOv8实战宝典--星级指南:从入门到精通,您不可错过的技巧   -- 聚焦于YOLO的 最新版本, 对颈部网络改进、添加局部注意力、增加检测头部,实测涨点 💡 深入浅出YOLOv8:我的专业笔记与技术总结   -- YOLOv8轻松上手, 适用技术小白,文章代码齐全,仅需 …

海康威视监控相机的SDK与opencv调用(非工业相机)

1.研究内容 本篇主要对海康威视的监控相机的SDK回调进行研究&#xff0c;并于opencv结合&#xff0c;保存图像,以供后续其他处理&#xff0c;开发语言为C 2.步骤及方法 2.1 海康SDK介绍 海康SDK下载地址 根据自身编译环境&#xff0c;下载对应的SDK&#xff0c;需要注意的是…

rotation matrix reflection matrix

文章目录 1. rotation matrix1.1 结论 2. reflection matrix2.1 结论 1. rotation matrix 图像逆时针旋转 θ \theta θ的矩阵 Q r o t a t e [ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ] (1) Q_{rotate}\begin{bmatrix}\cos\theta&-\sin\theta\\\sin\theta&\c…

LOJ #10134. 「一本通 4.4 练习 1」Dis

分析 根据数据范围分析一下复杂度&#xff0c;Floyd和dj算法都必爆。 发现题目说的是树&#xff0c;还是边还是双向的&#xff08;树本身就是无向的&#xff0c;连通无回路的无向图叫做无向树&#xff0c;简称树。如果题目说了树&#xff0c;那么默认边就是双向的&#xff09…

腾讯云服务器标准型S5实例CPU性能如何?配置特性说明

腾讯云服务器CVM标准型S5实例具有稳定的计算性能&#xff0c;CVM 2核2G S5活动优惠价格280.8元一年自带1M带宽&#xff0c;15个月313.2元、2核4G配置748.2元15个月&#xff0c;CPU内存配置还可以选择4核8G、8核16G等配置&#xff0c;公网带宽可选1M、3M、5M或10M&#xff0c;腾…

uniapp和vue3+ts创建自定义下拉选择框组件

使用uniapp开发小程序的时候&#xff0c;使用了uview的ui组件&#xff0c;但是里面没有下拉选择组件&#xff0c;只有Picker 选择器&#xff0c;但是我们想要使用下拉选择的组件&#xff0c;所以需要自定义个一个下拉选择的自定义组件&#xff0c;我就只能自己动手创建这个自定…

公网环境固定域名异地远程访问内网BUG管理系统

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

【OpenGauss源码学习 —— 列存储(ColumnTableSample)】

执行算子&#xff08;ColumnTableSample&#xff09; 概述ColumnTableSample 类ColumnTableSample::ColumnTableSample 构造函数ColumnTableSample::~ColumnTableSample 析构函数ExecCStoreScan 函数ColumnTableSample::scanVecSample 函数ColumnTableSample::getMaxOffset 函数…

前端实现移动端Tab栏(附带源码)

文章目录 先上图,附带源码index.html 主要视图层Main.css 主要样式demo.css主要的JS,在index.html 引入即可先上图,附带源码 提示:一款JS和CSS3炫酷Tabbar导航栏动画特效。该Tabbar导航栏在点击切换时,会有类似波浪运动的动画效果,非常炫酷。 index.html 主要视图层 &l…

Hadoop-- hdfs

1、HDFS中的三个进程&#xff1a;NameNode&#xff08;NN&#xff09;、DataNode(DN)、SecondNameNode(SNN) 2、NameNode&#xff08;NN&#xff09; 1、作用&#xff1a; 1、接收客户端的一个读、写的服务&#xff0c;在namenode上存储了数据文件和datanode的映射的关系。 …

Python实现WOA智能鲸鱼优化算法优化随机森林回归模型(RandomForestRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 鲸鱼优化算法 (whale optimization algorithm,WOA)是 2016 年由澳大利亚格里菲斯大学的Mirjalili 等提…

[C语言 数据结构] 栈

1.什么是栈&#xff1f; 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压…

Java高级编程-----网络编程

网络通信协议 通过计算机网络可以实现多台计算机连接&#xff0c;但是不同计算机的操作系统和硬件体系结构不同&#xff0c;为了提供通信支持&#xff0c;位于同一个网络中的计算机在进行连接和通信时必须要遵守一定的规则&#xff0c;这就好比在道路中行驶的汽车一定要遵守交…

C++ LibCurl实现Web隐藏目录扫描

LibCurl是一个开源的免费的多协议数据传输开源库&#xff0c;该框架具备跨平台性&#xff0c;开源免费&#xff0c;并提供了包括HTTP、FTP、SMTP、POP3等协议的功能&#xff0c;使用libcurl可以方便地进行网络数据传输操作&#xff0c;如发送HTTP请求、下载文件、发送电子邮件等…

Android AIDL中使用Surface问题

1.构建ITest.aidl文件 package com.xxx.xxxx;import android.view.Surface;interface IMonitorService {boolean addSurface(in Surface surface);boolean removeSurface(in Surface surface); } 2.构建时报错 3.Surface源码分析 android.view.Surface中包含两个Surface类&am…

泛型进阶:通配符

基本概念 对泛型不了解的可以看这篇博客&#xff1a;数据结构前瞻-CSDN博客 一般来说&#xff0c;&#xff1f;在泛型里的使用就是通配符 看看下面的代码 class Message<T> {private T message ;public T getMessage() {return message;}public void setMessage(T m…

新生儿斜视:原因、科普和注意事项

引言&#xff1a; 新生儿斜视是一种儿童眼部常见的问题&#xff0c;指的是眼球的定位不正常&#xff0c;造成双眼无法同时注视同一个物体。了解新生儿斜视的原因、科普相关知识&#xff0c;并提供适当的注意事项&#xff0c;对于早期发现和处理这一问题至关重要。本文将深入探…

通过css设置元素隐藏和显示

背景&#xff1a;鼠标悬浮时显示删除&#xff0c;放开后显示组件名 解决&#xff1a;通过display:none和display:block显示和隐藏元素&#xff1b; 使用 div p选择器选择当前div的下一个紧跟的p元素 <div v-if"!preview" class"name">{{propertyDa…