本文目录导读:

跨域策略(CORS,Cross-Origin Resource Sharing)是浏览器实施的一种安全机制,用于限制来自不同源(协议、域名或端口不同)的网页对当前服务器资源的访问。安全配置的核心原则是:只允许可信的源访问,且只暴露必要的资源和方法。
如果配置不当,可能会导致数据泄露、CSRF(跨站请求伪造)攻击等严重问题,以下是如何安全配置CORS的详细指南。
核心配置项与安全原则
CORS通过HTTP响应头来控制,服务器需要设置以下几个关键的响应头:
Access-Control-Allow-Origin(最重要)- 作用:指定哪些源(
Origin)可以访问资源。 - 安全配置:
- *绝不要使用通配符 `
**:除非你的API是**完全公开**的、无状态的静态资源(如公共CDN、字体文件)。*` 会允许任何网站读取你的响应。 - 白名单机制:动态设置该头,只返回你明确信任的源(如你的前端域名)。
Access-Control-Allow-Origin: https://www.your-frontend.com。 - 动态验证:检查请求头中的
Origin是否在你的白名单中,如果在,则将Origin的值直接作为Access-Control-Allow-Origin返回。注意:不要直接无条件回显Origin,这同样会产生 的效果。
- *绝不要使用通配符 `
- 作用:指定哪些源(
Access-Control-Allow-Methods- 作用:指定允许的HTTP方法(如
GET,POST,PUT,DELETE)。 - 安全配置:只开放你的API实际需要的方法,如果接口只提供查询,则只需
GET和HEAD,不要滥用 。
- 作用:指定允许的HTTP方法(如
Access-Control-Allow-Headers- 作用:指定浏览器在预检请求中允许携带的自定义请求头(如
Authorization,X-Custom-Header)。 - 安全配置:只列出你的应用实际需要的请求头,如果使用JWT做认证,就需要包含
Authorization,如果不需要,就留空或使用最小集合。
- 作用:指定浏览器在预检请求中允许携带的自定义请求头(如
Access-Control-Allow-Credentials- 作用:控制是否允许浏览器在跨域请求中发送Cookie、HTTP认证信息等凭证。
- 安全配置:
- 默认不设置或设为
false,除非你的API明确需要依赖Cookie进行身份验证(如基于Session的认证)。 - *如果设为
true,则Access-Control-Allow-Origin不能为 `**,必须明确指定具体的源域名(如https://www.your-frontend.com`)。
- 默认不设置或设为
Access-Control-Max-Age- 作用:指定预检请求(OPTIONS请求)的结果可以被缓存多久(单位秒)。
- 安全配置:设置一个合理的有限时间(如 600 秒或 3600 秒),过长的缓存时间可能导致你的策略更新后,浏览器端依然使用旧策略,从而产生安全隐患或功能异常。
安全配置步骤
服务器端实现(示例)
后端框架示例(Node.js + Express):
const express = require('express');
const app = express();
// 白名单配置(从环境变量或配置文件读取)
const ALLOWED_ORIGINS = [
'https://www.your-frontend.com',
'https://app.your-frontend.com',
'http://localhost:3000' // 开发环境
];
app.use((req, res, next) => {
const origin = req.headers.origin;
// 1. 验证 Origin
if (origin && ALLOWED_ORIGINS.includes(origin)) {
// 安全:只对白名单中的源设置精确的 Origin
res.setHeader('Access-Control-Allow-Origin', origin);
// 如果使用 Cookie 认证,需将此项设为 true,且 Origin 不能是 *
res.setHeader('Access-Control-Allow-Credentials', 'true');
} else {
// 对于不信任的 Origin,不设置 CORS 头,浏览器会拒绝
// 或者也可以设置一个占位,但绝大多数框架不会,保持默认即可
}
// 2. 处理预检请求 (OPTIONS)
if (req.method === 'OPTIONS') {
// 只开放必要的 HTTP 方法
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
// 只开放需要自定义的请求头,如果只传 JSON,可能只需要 'Content-Type'
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 缓存预检请求结果 1 小时(3600秒)
res.setHeader('Access-Control-Max-Age', '3600');
// 预检请求直接返回 204 No Content
res.status(204).end();
} else {
next();
}
});
// 你的 API 路由
app.get('/api/user', (req, res) => {
res.json({ name: 'Alice' });
});
其他常见场景配置
- 使用反向代理(如 Nginx):通常在Nginx层统一配置CORS,配置逻辑同上,使用
add_header指令,并通过$http_origin变量实现动态白名单校验。 - 使用云服务/API网关:大部分云服务(AWS API Gateway, Cloudflare, Azure API Management)都提供了CORS配置面板,推荐使用这些托管服务来配置,它们通常会内置安全校验。
浏览器端注意事项
- 不要在前端代码中额外设置
Origin头(浏览器会自动设置且无法被修改)。 - 正确设置
withCredentials: true:如果后端要求凭证,前端在fetch或XMLHttpRequest中需要显式设置credentials: 'include'(fetch)或withCredentials: true(XHR)。但请不要随意开启,除非你真的需要发送Cookie。 - 预检请求:对于非简单请求(非
GET/HEAD/POST且Content-Type不是application/x-www-form-urlencoded,multipart/form-data,text/plain),浏览器会先发一个OPTIONS请求,后端需要正确处理它。
常见安全陷阱与建议
| 不安全做法 | 风险 | 正确做法 |
|---|---|---|
Access-Control-Allow-Origin: * |
任何网站都能读取你的API响应 | 使用白名单,精确指定源 |
直接回显 Origin 头(如 res.setHeader('Access-Control-Allow-Origin', req.headers.origin)) |
如果攻击者伪造 Origin 头,服务器直接信任,等同于 |
必须与白名单比对后再回显 |
Access-Control-Allow-Credentials: true 且 Origin: * |
浏览器会忽略该配置导致凭证无法携带,或更糟糕的,某些错误实现下不安全 | 必须同时指定精确的 Origin |
过度开放 Access-Control-Allow-Methods |
虽然风险较小,但增加攻击面 | 只开放实际需要的HTTP方法(如 GET, POST) |
Access-Control-Max-Age 设得过大(如14400秒)或过小 |
过大导致策略更新延迟,过小增加预检请求数量影响性能 | 设置为 600 - 3600 秒(10分钟至1小时) |
安全配置清单
- 建立白名单:明确记录所有需要访问的前端源(域名、协议、端口必须完全一致)。
- 动态验证:在服务器中间件中,从请求头取出
Origin,与白名单比对,匹配则返回该Origin,不匹配则不返回任何 CORS 头。 - 最小权限:只开放必要的
Methods和Headers。 - 谨慎处理凭据:如果必须使用Cookie认证,
Credentials: true必须配合精确的Origin。 - 控制预检缓存:设置合理的
Max-Age(如600秒)。 - 日志与监控:记录被拒绝的
Origin请求,监控异常访问模式(如大量来自未知域的请求)。 - 避免前端直接配置CORS:CORS是服务器的配置,前端无法绕过它。
最终建议:如果条件允许,使用API网关或反向代理来统一管理CORS策略,它们通常提供了更完善的校验和日志能力,且可以避免在业务代码中分散处理安全逻辑。