Node.js + Koa跨域携带Cookies实战指南
Node.js + Koa实现跨域(域名不同,端口不同)携带Cookies全攻略
一、跨域场景与Cookie安全挑战
在前后端分离架构中,跨域请求(不同域名或端口)是常见场景。当需要携带身份验证的Cookie时,浏览器会因同源策略拦截请求。例如前端部署在http://frontend.com:3000,后端API在http://api.example.com:8000,常规请求会丢失Cookie。
1.1 跨域通信原理
浏览器通过HTTP请求头中的Origin字段标识来源,服务器响应时需通过Access-Control-Allow-*系列头明确允许跨域。当涉及Cookie时,需额外处理credentials模式。
1.2 Cookie安全三要素
实现跨域Cookie传递需同时满足:
- 服务器设置
Access-Control-Allow-Credentials: true - 响应头包含
Access-Control-Allow-Origin(不能为*) - Cookie属性包含
SameSite=None; Secure
二、Koa中间件配置方案
2.1 基础CORS中间件
使用@koa/cors中间件简化配置:
const Koa = require('koa');const cors = require('@koa/cors');const app = new Koa();app.use(cors({origin: 'http://frontend.com:3000', // 精确匹配前端域名credentials: true, // 允许携带凭证allowMethods: ['GET', 'POST', 'PUT', 'DELETE']}));
2.2 自定义CORS中间件(进阶)
当需要动态控制时,可自定义中间件:
app.use(async (ctx, next) => {const allowedOrigins = ['http://frontend.com:3000','https://staging.frontend.com'];const origin = ctx.headers.origin;if (allowedOrigins.includes(origin)) {ctx.set('Access-Control-Allow-Origin', origin);ctx.set('Access-Control-Allow-Credentials', 'true');ctx.set('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');ctx.set('Access-Control-Allow-Headers', 'Content-Type,Authorization');}await next();});
三、Cookie属性深度配置
3.1 服务器端设置Cookie
使用koa-cookie中间件设置安全Cookie:
const cookie = require('koa-cookie');app.use(cookie());// 设置跨域Cookieapp.use(async (ctx) => {ctx.cookies.set('auth_token', 'xyz123', {domain: '.example.com', // 父域名共享path: '/',secure: true, // 必须HTTPSsameSite: 'none', // 允许跨域httpOnly: true, // 防止XSSmaxAge: 86400000 // 24小时有效期});});
3.2 前端请求配置
Axios请求需设置withCredentials:
axios.get('https://api.example.com/data', {withCredentials: true}).then(response => {console.log(response.data);});
四、安全验证与最佳实践
4.1 双重验证机制
- CSRF Token验证:在Cookie中存储CSRF Token,表单提交时校验
- JWT签名验证:结合JWT实现无状态认证
// JWT中间件示例const jwt = require('jsonwebtoken');app.use(async (ctx, next) => {const token = ctx.cookies.get('auth_token');try {const decoded = jwt.verify(token, process.env.JWT_SECRET);ctx.state.user = decoded;await next();} catch (err) {ctx.status = 401;ctx.body = { error: 'Unauthorized' };}});
4.2 HTTPS强制配置
生产环境必须启用HTTPS:
const https = require('https');const fs = require('fs');const options = {key: fs.readFileSync('private-key.pem'),cert: fs.readFileSync('certificate.pem')};https.createServer(options, app.callback()).listen(443);
五、常见问题解决方案
5.1 预检请求(OPTIONS)处理
浏览器会在实际请求前发送OPTIONS预检请求,需确保服务器正确处理:
app.use(async (ctx, next) => {if (ctx.method === 'OPTIONS') {ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);ctx.set('Access-Control-Allow-Credentials', 'true');ctx.status = 204; // No Contentreturn;}await next();});
5.2 子域名Cookie共享
设置domain属性实现父域名共享:
// 设置可在所有子域名共享的Cookiectx.cookies.set('session_id', 'abc456', {domain: '.example.com', // 包括api.example.com, admin.example.com等sameSite: 'none',secure: true});
六、完整实现示例
6.1 服务器端完整代码
const Koa = require('koa');const cors = require('@koa/cors');const cookie = require('koa-cookie');const jwt = require('jsonwebtoken');const app = new Koa();// 中间件配置app.use(cookie());app.use(cors({origin: 'http://frontend.com:3000',credentials: true}));// 模拟登录接口app.use(async (ctx) => {if (ctx.path === '/login' && ctx.method === 'POST') {// 生成JWT Tokenconst token = jwt.sign({ userId: '123', role: 'admin' },process.env.JWT_SECRET,{ expiresIn: '1h' });// 设置安全Cookiectx.cookies.set('auth_token', token, {httpOnly: true,secure: process.env.NODE_ENV === 'production',sameSite: 'none',maxAge: 3600000});ctx.body = { success: true };}});app.listen(8000, () => {console.log('Server running on http://localhost:8000');});
6.2 前端调用示例
// 登录请求async function login() {const response = await fetch('https://api.example.com/login', {method: 'POST',credentials: 'include',headers: {'Content-Type': 'application/json'},body: JSON.stringify({ username: 'admin', password: '123456' })});if (response.ok) {// 登录成功后获取受保护数据const data = await fetch('https://api.example.com/protected', {credentials: 'include'});console.log(await data.json());}}
七、性能优化建议
- Cookie大小控制:单个域名Cookie总量建议不超过4KB
- Session存储优化:敏感数据存放在JWT中,非敏感数据使用Cookie
- CDN加速:对静态资源使用CDN分发,减少主域名压力
- HTTP/2启用:提升多资源加载性能
八、安全审计清单
- 验证所有跨域请求是否包含
withCredentials - 检查Cookie是否设置
HttpOnly和Secure标志 - 确认JWT签名密钥定期轮换
- 审计允许的跨域域名列表
- 监控异常的跨域请求频率
通过以上系统化的配置和验证,开发者可以在Node.js + Koa环境中实现安全可靠的跨域Cookie传递,为前后端分离架构提供坚实的身份验证基础。实际部署时,建议结合具体业务场景进行安全加固和性能调优。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权请联系我们,一经查实立即删除!