跨域问题解决方案汇总
2025年11月15日 21:17
跨域 / 同源策略概述 **同源(same-origin)**:协议、域名(host)、端口 三者完全相同称为同源。 例如 https://example.com:443 和 http://exa
sessionId 对应的对象存在 Redis / DB / 内存),并返回 Set-Cookie: sessionId=xxx; HttpOnly; Secure; SameSite=Lax; Path=/ 响应头部信息。credentials: 'include'),后端根据 sessionId 在 session store 查到用户信息并授权。后端:
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
name: 'sid',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: true, // 生产必须 https
sameSite: 'lax', // 或 'strict' / 'none'(配合跨域)
maxAge: 24 * 3600 * 1000
}
}));
前端(fetch):
fetch('/api/profile', { credentials: 'include' })
Access-Control-Allow-Credentials、Set-Cookie 的 SameSite=None; Secure 等,避免安全问题。JWT 典型格式:header.payload.signature(Base64 编码)
const jwt = require('jsonwebtoken');
const accessToken = jwt.sign({ uid: xxx }, process.env.JWT_SECRET, { expiresIn: '15m' });
const payload = jwt.verify(accessToken, process.env.JWT_SECRET);
Bearer <token>,或也可放在 HttpOnly cookie(同域 + credentials)
推荐将 Refresh Token 放 HttpOnly cookie,Access Token 放内存并通过 Authorization header 发送(减少 CSRF 风险)。
| 特性 | Cookie + Session(服务端) | JWT(无状态) |
|---|---|---|
| 主要存储位置 | 服务端(Redis) | 客户端持 token(或 cookie) |
| 是否无状态 | 否 | 是(默认) |
| 可撤销性 | 立刻可撤销(删除 session) | 需要黑名单等策略 |
| 扩展性(横向扩展) | 需外部 session store(redis 做 session 共享) | 天然适合横向扩展 |
| CSRF 风险 | 高(Cookie 自动带) | 如果 token 放 localStorage,CSRF 低但 XSS 高;如果 token 放 HttpOnly cookie,CSRF 风险同 Cookie Session |
| 操作复杂度 | 较低 | 较高(密钥管理、刷新策略) |
SameSite=None 的跨站场景,配合 **CSRF Token(双 submit cookie)**:
Set-Cookie: CSRF-Token=xxx; HttpOnly=false; Secure(可被 JS 读取)X-CSRF-Token: <value>,后端验证 header 与 cookie 值一致。Origin / Referer 检查(只允许来自可信域的请求)。核心:CSRF 攻击者 可以发请求,但 没法读 Cookie,无法把 token 放到 header 中,所以校验(
(req.cookies["CSRF-Token"] !== req.headers["X-CSRF-Token"]))。CSRF 攻击能发请求,但拿不到 cookie 内容 。
localStorage(HttpOnly cookie 防止 JS 读取)。