Cookie和Session介绍

Cookie和Session的区别

  Cookie 和 Session 都是用于存储用户状态和数据的技术,但它们在工作原理、存储位置、安全性等方面有显著区别。

Cookie

存储位置:Cookie 存储在客户端(用户的浏览器)中。
存储大小:每个 Cookie 的大小限制在约 4KB。
生命周期:Cookie 可以设置过期时间(例如,几分钟、几小时或几年)。在过期时间之前,Cookie 会一直保存在客户端,除非被用户手动删除。
安全性:Cookie 可以很容易被用户查看和修改,因此存储在 Cookie 中的数据应该避免包含敏感信息。
支持 HTTPS 安全传输,通过设置 Secure 标志和 HttpOnly 标志可以提高安全性。
应用场景:适用于需要在客户端持久化存储少量数据的场景,比如记住用户的登录状态、用户偏好设置、跟踪用户行为等。用于跨会话存储信息,因为 Cookie 可以设置较长的过期时间

Session

存储位置:Session 数据存储在服务器端。客户端只保存一个唯一的 Session ID,这个 ID 存储在 Cookie 中(或 URL 中,但不推荐)。
存储大小:服务器端存储的大小只受服务器存储能力的限制,相对于 Cookie,可以存储更多的数据。
生命周期:Session生命周期通常较短,一般与用户的浏览器会话一致。当用户关闭浏览器或会话超时(没有活动一定时间),Session会失效。
安全性:Session 数据存储在服务器端,用户无法直接访问,因此安全性更高。Session ID 可以通过 HTTPS 安全传输,防止被窃取。
应用场景:适用于需要存储敏感信息和较大量数据的场景,如用户的登录信息、购物车、用户偏好等。适用于需要高安全性的场景,因为数据存储在服务器端,避免了客户端的安全风险。

Cookie和Session在登陆场景中的使用

  cookie和ssession虽然有一定的区别,但是实际场景中,cookie和session经常搭配使用。下图来源于极客时间专栏,下图是登陆场景中cookie和session搭配使用情况。在登陆场景中,调用login的接口,在数据库中存入用户登陆状态,并通过Set-Cookie把sessionID传递到客户端,客户端在cookie中存储了sessionId信息,后续用户在访问其他请求的时候,通过解析session,就可以知道用户当前的登陆状态。总结而言,两者虽然有区别,但又经常配合一起使用。

  以下图为例,这里是访问极客时间网站,可以看到在这个请求中通过Set-Cookie,将ServerID设置到了cookie中。在后续的请求中,Request中cookie的值里面,就包含了ServerID这个键值对。

Cookie的属性和使用

是实际使用中,除了上面的Path属性,Cookie还有很多其他属性,具体如下所示:

Name:Cookie 的名称,是一个唯一标识符。Value:Cookie 的值,存储实际的数据内容。
Domain:指定 Cookie 可以使用的域名。如果没有指定,默认是当前请求的域名。
Path:指定 Cookie 的作用路径。只有路径匹配的请求才会携带这个 Cookie。如果没有指定,默认是当前请求的路径。
Expires:设定 Cookie 的过期时间,是一个具体的日期时间点。例如 Expires=Wed, 21 Oct 2025 07:28:00 GMT。
Max-Age:设定 Cookie 的有效期,是一个相对于当前时间的秒数。例如 Max-Age=3600 表示 Cookie 会在一小时后过期。如果设置了 Max-Age,则 Expires 会被忽略。
Secure:指定 Cookie 只能通过 HTTPS 传输,确保 Cookie 在传输过程中不会被窃取。只有在使用 HTTPS 协议时,浏览器才会发送这个 Cookie。
HttpOnly:指定 Cookie 不能通过 JavaScript 的 Document.cookie 访问,减少跨站脚本攻击(XSS)风险。
SameSite:控制 Cookie 在跨站请求时的行为。可以设置为:
Strict:Cookie 在跨站请求时不会被发送。
Lax:Cookie 在一定条件下(如导航到目标站点的链接)会被发送。
None:Cookie 总是会被发送,但需要同时设置 Secure 属性。

Cookie和Session实际代码演示

 下面通过一个实际例子来演示如何在登陆场景中配合使用cookie和session存储用户状态信息。这里使用Nodejs来构建一个简单的web应用。下面的命令是初始化代码,并安装必要的包。

npm init -y
npm install express express-session cookie-parser body-parser

  下面的代码中创建了一个包含用户名和密码的登陆界面,输入正确的用户名和密码后,点击登录按钮,跳转到dashboard界面。再点击logout按钮,重新跳转到登录页面。在app.use中设置了要使用sessionId,这里的secret只是一个简单的字符串,实际项目,需要用一些加密算法加密字符串,并将密钥通过环境变量来读取。不能明文存放在代码中。在app.use中还设置了cookie的maxAge,secure,httpOnly,sameSite等属性。

import express from 'express';
import session from 'express-session';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';

const app = express();
const PORT = 3000;
// 使用 cookie-parser 中间件
app.use(cookieParser());
// 使用 body-parser 中间件
app.use(bodyParser.urlencoded({ extended: true }));
// 配置 Session 中间件
app.use(session({
    name: 'sessionId',
    secret: 'your_secret_key',
    resave: false,
    saveUninitialized: false,
    cookie: {
        maxAge: 24 * 60 * 60 * 1000, // Cookie 有效期为 1 天
        secure: false, // 仅在 HTTPS 连接上发送 Cookie
        httpOnly: true, // 禁止客户端 JavaScript 访问 Cookie
        sameSite: 'lax' // 控制 Cookie 是否随跨站请求发送
    }
}));
// 模拟用户数据库
const users = {
    'user1': 'user1',
    'user2': 'password2'
};
// 登录页面路由
app.get('/login', (req, res) => {
    res.send(`
        <form method="post" action="/login">
            <label for="username">Username:</label>
            <input type="text" id="username" name="username" required>
            <br>
            <label for="password">Password:</label>
            <input type="password" id="password" name="password" required>
            <br>
            <button type="submit">Login</button>
        </form>
    `);
});
// 处理登录请求的路由
app.post('/login', (req, res) => {
    const { username, password } = req.body;
    if (users[username] && users[username] === password) {
        req.session.user = username;
        res.redirect('/dashboard');
    } else {
        res.send('Invalid username or password');
    }
});
// 受保护的路由
app.get('/dashboard', (req, res) => {
    if (req.session.user) {
        res.send(`
            <h1>Welcome, ${req.session.user}!</h1>
            <a href="/logout">Logout</a>
        `);
    } else {
        res.redirect('/login');
    }
});
// 注销路由
app.get('/logout', (req, res) => {
    req.session.destroy(err => {
        if (err) {
            return res.send('Error logging out');
        }
        res.clearCookie('sessionId');
        res.redirect('/login');
    });
});
// 启动服务器
app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

执行命令“node ./app.js”启动应用后,浏览器中输入“http://localhost:3000/login”后,即可访问web应用了。

  输入用户名和密码,跳转到dashboard界面,调用login接口的时候,通过Set-Cookie,将最新的SessionId信息设置到cookie中。

  访问dashboard界面,Cookie中的sessionId值,已经是最新的值。另外,Dashboard界面的username名称就是通过session传递后,在页面上显示了“Welcome,xxx”。

 点击logout后,因为代码将cookie中的sessionId键清理了,可以看到在Request中确实没有sessionid字段了。

  除了通过cookie和session配置在登陆场景中使用外,cookie还可以记录用户行为信息。下面的代码中通过cookie记录用户访问次数和最近一次访问时间的行为信息。

import express from 'express';
import cookieParser from 'cookie-parser';

const app = express();
const PORT = 3001;
// 使用 cookie-parser 中间件
app.use(cookieParser());
// 主页路由
app.get('/', (req, res) => {
    // 获取现有的用户行为数据
    let userBehavior = req.cookies.userBehavior;
    if (!userBehavior) {
        userBehavior = { visits: 0, lastVisit: new Date().toISOString() };
    } else {
        userBehavior = JSON.parse(userBehavior);
    }
    // 更新用户行为数据
    userBehavior.visits += 1;
    userBehavior.lastVisit = new Date().toISOString();
    // 设置新的 Cookie,过期时间为 30 天
    res.cookie('userBehavior', JSON.stringify(userBehavior), { maxAge: 30 * 24 * 60 * 60 * 1000, httpOnly: true });
    // 响应用户行为数据
    res.send(`
        <h1>欢迎访问本站!</h1>
        <p>您已访问本站 ${userBehavior.visits} 次</p>
        <p>上次访问时间:${userBehavior.lastVisit}</p>
    `);
});

// 启动服务器
app.listen(PORT, () => {
    console.log(`服务器已启动,访问 http://localhost:${PORT}`);
});

实际项目中cookie和session使用场景

下面列举了实际应用中cookie和session具体存储了哪些内容,便于大家更容易理解cookie和session。

cookie
如果用户选择了“记住我”选项,可以存储一个长期有效的令牌,用于自动登录。示例:sessionId=abc123; Path=/; HttpOnly
存储用户的 Session ID,以便服务器可以识别用户的会话。示例:rememberMe=xyz456; Expires=Wed, 21 Oct 2025 07:28:00 GMT; Secure; HttpOnly
存储用户界面设置,如显示货币、语言偏好等。示例:currency=USD; Path=/; Expires=Wed, 21 Oct 2025 07:28:00 GMT
用于记录用户行为,如浏览的产品、页面等,用于分析和个性化推荐。示例:lastViewedProduct=prod123; Path=/; Expires=Wed, 21 Oct 2025 07:28:00 GMT

session
存储用户的登录状态和相关信息。示例:{ userId: 'user123', email: 'user@example.com', loggedInAt: '2024-07-17T10:00:00Z' }
存储跨站请求伪造(CSRF)令牌,防止CSRF攻击。示例:{ csrfToken: 'a1b2c3d4e5' }
存储用户当前会话中的临时数据,如正在编辑的文章。示例:{ draftPostId: 'post789', draftContent: 'This is a draft post.' }

针对cookie和session如何开展测试活动

  测试 Cookie 和 Session 主要涉及验证它们的创建、管理、过期和安全性。在实际项目中,可以通过单元测试和端到端测试来覆盖这些方面。在单元测试中可以重点检查cookie的属性设置是否正确,是否被成功创建或者销毁。在端到端测试中,需要依托cookie和session具体所设计的业务场景来开展测试,以登陆场景为例。重点关注用户是否能正常登陆,登陆在过期后会失效,需要重新登陆,登出后session,cookie数据被清理等重点。

  • 完整的用户登录流程

    • 模拟用户从登录页面进行登录,并验证登录后的页面和 Cookie、Session 的状态。
  • 受保护页面的访问

    • 模拟用户登录后访问受保护页面,验证页面加载和 Session 的状态。
    • 验证未登录用户访问受保护页面时的重定向和提示信息。
  • 用户注销流程

    • 模拟用户从受保护页面进行注销,并验证注销后的页面和 Cookie、Session 的状态。

  另外,安全方面,cookie属性中,有一些是安全相关的,可以通过浏览器检查这些属性是否正确设置。例如HttpOnly,Security,Samesite,确保设置合理的过期时间,避免长期有效的敏感 Cookie,如果cookie中存储了敏感数据,需要进行加密处理。session验证,可重点关注这些点:确保 Session ID 具有足够的随机性和唯一性,防止会话劫持,生成多个 Session ID,并检查其随机性和唯一性。确保会话在一段时间不活动后自动过期。在用户身份验证后更新 Session ID,防止会话固定攻击,即验证登录后是否生成新的 Session ID。验证会话数据是否仅在服务器端存储,不会泄露到客户端。在会话中存储和验证 CSRF 令牌,防止 CSRF 攻击。

以上就是对cookie,session方面的总结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

taoli-qiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值