面试题答案
一键面试会话一致性问题
- 问题描述:在分布式环境中,不同的服务器实例可能处理同一个用户的不同请求。如果会话数据仅存储在单个服务器实例的内存中,当用户请求切换到其他实例时,会话数据无法共享,导致会话不一致。
- 优化策略:
- 使用分布式缓存:如 Redis。将会话数据存储在 Redis 中,各个服务器实例都从 Redis 读取和写入会话数据,确保数据一致性。
- 粘性会话(Sticky Session):通过负载均衡器,将来自同一个客户端的请求始终路由到同一个服务器实例。但这种方法存在单点故障风险,如果该实例出现问题,用户会话将受影响。
Cookie 安全隐患
- 跨站脚本攻击(XSS):攻击者可注入恶意脚本,窃取用户 Cookie 中的敏感信息,如会话 ID。
- 跨站请求伪造(CSRF):攻击者利用用户已登录的会话,伪造请求,在用户不知情的情况下执行操作。
- 中间人攻击(MITM):攻击者拦截网络通信,窃取或篡改 Cookie 数据。
安全策略
- 针对 XSS:
- 输入验证和输出编码:对用户输入进行严格验证,确保不包含恶意脚本。对输出内容进行编码,防止脚本注入。
- 设置 HttpOnly 属性:将 Cookie 的 HttpOnly 属性设置为 true,这样 JavaScript 无法访问 Cookie,降低 XSS 攻击窃取 Cookie 的风险。
- 针对 CSRF:
- 添加 CSRF 令牌:在表单和 AJAX 请求中添加 CSRF 令牌。服务器验证请求中的令牌与用户会话中的令牌是否匹配,不匹配则拒绝请求。
- 针对 MITM:
- 使用 HTTPS:加密通信链路,防止中间人窃取或篡改 Cookie 数据。
示例:使用 Redis 解决会话一致性问题并保障 Cookie 安全
- 安装依赖:
npm install express redis cookie-parser
- 代码示例:
const express = require('express');
const redis = require('redis');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
// 连接 Redis
const redisClient = redis.createClient();
// 模拟登录
app.post('/login', (req, res) => {
const userId = req.body.userId;
const sessionId = 'unique_session_id'; // 实际应用中应生成唯一 ID
// 将会话数据存储到 Redis
redisClient.set(sessionId, userId, 'EX', 3600); // 设置过期时间为 1 小时
// 设置带有 HttpOnly 属性的 Cookie
res.cookie('sessionId', sessionId, { httpOnly: true });
res.send('Login successful');
});
// 验证会话
app.get('/protected', (req, res) => {
const sessionId = req.cookies.sessionId;
if (!sessionId) {
return res.status(401).send('Unauthorized');
}
redisClient.get(sessionId, (err, userId) => {
if (err ||!userId) {
return res.status(401).send('Unauthorized');
}
res.send(`Welcome, user ${userId}`);
});
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
在上述示例中,通过 Redis 存储会话数据,实现了分布式环境下的会话一致性。同时,通过设置 httpOnly
属性保障了 Cookie 的安全,防止 XSS 攻击窃取会话 ID。在请求验证时,从 Redis 中获取会话数据,确保用户请求的合法性。