Node.js与Koa跨域Cookie共享全攻略

作者:有好多问题2025.10.31 10:59浏览量:2

简介:本文深入解析Node.js+Koa框架下实现跨域(不同域名/端口)Cookie共享的技术方案,包含CORS配置、Cookie属性设置及安全实践,提供完整代码示例与部署建议。

Node.js与Koa跨域Cookie共享全攻略

在微服务架构和前后端分离开发中,跨域请求已成为常态。当API服务(如api.example.com:3000)与前端应用(如app.example.org:8080)存在域名或端口差异时,浏览器默认会阻止携带Cookie的跨域请求。这种安全机制虽然防止了CSRF攻击,但也给需要身份验证的API调用带来挑战。

典型问题场景

  1. 会话保持失效:登录状态无法通过Cookie维持
  2. JWT验证受阻:基于Cookie的JWT令牌无法传递
  3. CSRF令牌缺失:安全令牌无法跨域传输

二、Koa框架下的CORS核心配置

Koa通过@koa/cors中间件实现跨域控制,需重点配置以下参数:

  1. const Koa = require('koa');
  2. const cors = require('@koa/cors');
  3. const app = new Koa();
  4. app.use(cors({
  5. origin: function(ctx) {
  6. // 动态匹配允许的域名
  7. const allowedOrigins = [
  8. 'https://app.example.org',
  9. 'http://localhost:8080'
  10. ];
  11. const origin = ctx.request.header.origin;
  12. return allowedOrigins.includes(origin) ? origin : false;
  13. },
  14. credentials: true, // 关键配置:允许携带凭证
  15. allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
  16. allowHeaders: ['Content-Type', 'Authorization'],
  17. exposeHeaders: ['Content-Length', 'X-Koa-Version'],
  18. maxAge: 86400 // 预检请求缓存时间(秒)
  19. }));

配置要点解析

  1. origin动态验证:比对请求来源与白名单,避免硬编码风险
  2. credentials标志:必须设为true才能传输Cookie
  3. 预检请求处理:复杂请求会先发送OPTIONS请求,需正确响应

仅配置CORS还不够,需同时设置Cookie的以下属性:

  1. const session = require('koa-session');
  2. app.keys = ['your-secret-key'];
  3. app.use(session(app, {
  4. key: 'koa:sess',
  5. maxAge: 86400000, // 24小时
  6. overwrite: true,
  7. httpOnly: true, // 防止XSS攻击
  8. secure: process.env.NODE_ENV === 'production', // 生产环境启用HTTPS
  9. sameSite: 'none' // 关键配置:允许跨域发送
  10. }));
  11. // 设置响应Cookie示例
  12. ctx.cookies.set('auth_token', 'abc123', {
  13. domain: '.example.com', // 子域名共享(需谨慎)
  14. path: '/',
  15. httpOnly: true,
  16. secure: true,
  17. sameSite: 'none',
  18. maxAge: 3600000
  19. });
属性 可选值 作用说明
sameSite strict/lax/none strict: 完全禁止跨域
lax: 部分允许
none: 必须配合secure使用
secure true/false 仅HTTPS下传输,防止中间人攻击
httpOnly true/false 禁止JS访问,防范XSS
domain 字符串 指定可访问的域名(如.example.com允许所有子域)

四、完整实现示例

1. 服务端配置(Koa)

  1. const Koa = require('koa');
  2. const Router = require('@koa/router');
  3. const cors = require('@koa/cors');
  4. const session = require('koa-session');
  5. const app = new Koa();
  6. const router = new Router();
  7. // 会话配置
  8. app.keys = ['your-32-byte-long-secret-key'];
  9. app.use(session(app, {
  10. sameSite: 'none',
  11. secure: true
  12. }));
  13. // CORS配置
  14. app.use(cors({
  15. origin: (ctx) => {
  16. const allowed = ['https://app.example.org', 'http://localhost:8080'];
  17. return allowed.includes(ctx.request.header.origin) ? ctx.request.header.origin : false;
  18. },
  19. credentials: true
  20. }));
  21. // 登录接口
  22. router.post('/login', async (ctx) => {
  23. ctx.session.user = { id: 1, name: 'test' };
  24. ctx.cookies.set('session_id', '12345', {
  25. sameSite: 'none',
  26. secure: true,
  27. httpOnly: true
  28. });
  29. ctx.body = { success: true };
  30. });
  31. // 受保护接口
  32. router.get('/profile', async (ctx) => {
  33. if (!ctx.session.user) {
  34. ctx.status = 401;
  35. return;
  36. }
  37. ctx.body = { user: ctx.session.user };
  38. });
  39. app.use(router.routes());
  40. app.listen(3000);

2. 客户端调用(Fetch API)

  1. // 登录请求(携带凭证)
  2. async function login() {
  3. const response = await fetch('https://api.example.com:3000/login', {
  4. method: 'POST',
  5. credentials: 'include', // 必须设置
  6. headers: {
  7. 'Content-Type': 'application/json'
  8. },
  9. body: JSON.stringify({ username: 'test', password: '123' })
  10. });
  11. return response.json();
  12. }
  13. // 获取用户信息
  14. async function getProfile() {
  15. const response = await fetch('https://api.example.com:3000/profile', {
  16. credentials: 'include' // 必须设置
  17. });
  18. return response.json();
  19. }

五、生产环境安全实践

  1. HTTPS强制:所有跨域Cookie必须通过HTTPS传输
  2. CSRF防护:即使使用Cookie,仍建议实现CSRF令牌机制
  3. 子域名管理:谨慎使用.example.com通配符,避免权限过度开放
  4. 短期有效期:设置合理的Cookie过期时间(建议≤24小时)
  5. HttpOnly标志:防止XSS攻击获取Cookie内容

六、常见问题解决方案

检查项

  • 确认CORS配置包含credentials: true
  • 确认Fetch/XMLHttpRequest设置了credentials: 'include'
  • 检查Cookie的sameSite属性是否为nonesecuretrue

问题2:开发环境配置困难

解决方案

  • 本地开发时允许http://localhosthttp://127.0.0.1
  • 使用ngrok等工具生成HTTPS开发域名
  • 浏览器禁用安全策略(仅限测试环境)

配置示例

  1. ctx.cookies.set('shared_cookie', 'value', {
  2. domain: '.example.com', // 允许所有子域访问
  3. sameSite: 'lax', // 子域共享时推荐lax
  4. secure: true
  5. });

七、性能优化建议

  1. 预检请求缓存:合理设置maxAge减少OPTIONS请求
  2. Cookie体积控制:单个域名Cookie总量建议不超过4KB
  3. 会话存储优化:大数据量考虑使用JWT或Token替代session

八、替代方案对比

方案 优点 缺点
Cookie 浏览器自动管理,API简单 跨域配置复杂,有安全限制
LocalStorage 无跨域限制,容量大 需手动传输,XSS风险高
JWT 无状态,适合分布式系统 撤销困难,体积较大

通过本文的配置方案,开发者可以在Node.js+Koa环境中安全地实现跨域Cookie共享,既保持会话连续性,又符合现代Web安全标准。实际部署时,建议结合具体业务场景进行安全加固和性能调优。