本文目录导读:

- 核心响应头:
Access-Control-Allow-Origin - 处理凭据:
Access-Control-Allow-Credentials - 限制HTTP方法:
Access-Control-Allow-Methods - 限制自定义请求头:
Access-Control-Allow-Headers - 缓存预检请求:
Access-Control-Max-Age - 服务器端处理逻辑(举例:Node.js中间件)
- 进阶安全策略
- 安全CORS清单
跨域策略(CORS)安全配置的核心原则是最小权限原则:只允许你信任的源、只允许必须的HTTP方法、只暴露必要的数据、避免使用通配符,以下是从基础到进阶的安全配置指南。
核心响应头:Access-Control-Allow-Origin
这是最关键的头,它决定哪个外部源可以访问你的资源。
-
✅ 安全做法:明确指定具体域名
- 只对已知且必要的源授权。
- 正确示例:
Access-Control-Allow-Origin: https://your-frontend.example.com - 错误示例:
Access-Control-Allow-Origin: *(通配符)
-
*❌ 避免使用通配符 `` 的场景**
- 当请求中包含凭据(cookies、HTTP认证、客户端SSL证书)时,不允许使用 。
- 当资源是非公开(仅限登录用户使用)时。
- 当你需要根据请求动态返回源时(配合Origin头做验证)。
-
✅ 安全做法:动态验证请求头
- 服务器端应检查请求中的
Origin头,如果它在你的白名单中,则返回该具体源;否则返回错误或不设置CORS头。 - 关键逻辑:不要简单地原样返回
Origin头,必须做白名单验证。
- 服务器端应检查请求中的
处理凭据:Access-Control-Allow-Credentials
如果需要携带cookie或Authorization头进行跨域请求,此头必须设置为 true。
-
✅ 安全做法
Access-Control-Allow-Credentials: true- 同时必须:
Access-Control-Allow-Origin不能为 ,必须是具体的源。 - 同时必须:
Access-Control-Expose-Headers不能包含 ,必须是具体的头。 - 注意:如果后端有这个头,前端AJAX请求必须设置
withCredentials: true,否则浏览器会拒绝响应。
-
❌ 不安全做法
允许携带凭据的同时,源设置成 ,这是最常见的配置错误,浏览器会直接报错并阻止请求。
限制HTTP方法:Access-Control-Allow-Methods
仅允许你预期使用的HTTP方法。
- ✅ 安全做法
Access-Control-Allow-Methods: GET, POST, PUT- 避免
Access-Control-Allow-Methods: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PATCH - 特别要禁用
PUT、DELETE、PATCH如果业务不需要,如果业务需要,则保留。 - 更安全的做法:如果API只读,就只允许
GET。
限制自定义请求头:Access-Control-Allow-Headers
仅允许必要的、非简单的请求头。
- ✅ 安全做法
Access-Control-Allow-Headers: X-Custom-Header, Content-Type- 避免
Access-Control-Allow-Headers: *。
缓存预检请求:Access-Control-Max-Age
预检请求(OPTIONS)会增加一次往返,可以缓存它。
- ✅ 安全做法
- 设置一个合理的长时间(如
86400秒,即24小时)。 Access-Control-Max-Age: 86400
- 设置一个合理的长时间(如
服务器端处理逻辑(举例:Node.js中间件)
这是一个安全的CORS中间件示例逻辑,不依赖第三方库:
const ALLOWED_ORIGINS = [
'https://your-frontend.example.com',
'https://admin.your-app.com'
];
function corsMiddleware(req, res, next) {
const origin = req.headers.origin;
// 1. 检查Origin是否在白名单中
if (ALLOWED_ORIGINS.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
// 2. 凭据配置
res.setHeader('Access-Control-Allow-Credentials', 'true');
// 3. 处理预检请求
if (req.method === 'OPTIONS') {
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT');
// 只允许必要的请求头
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Max-Age', '86400'); // 24 hours
return res.status(204).end();
}
} else {
// 对于不在白名单的请求,通常不设置CORS头(浏览器会拒绝)
// 或者返回403,但更安全是不设置任何头
}
next();
}
// 使用
app.use(corsMiddleware);
进阶安全策略
- 不要信任
Origin头的格式:验证Origin的完全匹配,包括协议(https://)、域名、端口。http://evil.example.com与https://example.com不同。 - *禁止 `
与Credentials` 的混合**:这是最常见的安全漏洞。 - 限制暴露响应头:
Access-Control-Expose-Headers只暴露前端真正需要的响应头。 - 避免使用
Vary: Origin:如果动态返回源,建议主动设置Vary: Origin,但某些CDN或代理会缓存第一个请求的源,导致后续其他源被错误返回,更安全的做法是在CDN层不做CORS相关的缓存。 - 如果你的服务是静态资源(图片、CSS):如果资源完全是公开的(无需登录、无敏感数据),可以用
Access-Control-Allow-Origin: *,但即使如此,也要谨慎,因为其他网站可以嵌入。
安全CORS清单
| 配置项 | 推荐安全值 | 不安全/危险做法 |
|---|---|---|
| Access-Control-Allow-Origin | 具体的、白名单验证后的源 | 或直接返回未验证的 Origin |
| Access-Control-Allow-Credentials | true(仅在需要凭据时) |
与 一起使用 / 不必要地开启 |
| Access-Control-Allow-Methods | 业务需要的具体方法 | 或包含不必要的方法 |
| Access-Control-Allow-Headers | 业务需要的具体头 | 或包含敏感头 |
| Origin白名单验证 | 必须在服务器端做 | 完全不验证或任意匹配 |
| 预检请求处理 | 限制方法、头、Max-Age | 允许所有 |
安全配置不是一个静态的开关,而是一个动态的、基于业务需求的最小权限集合,定期审查你的 Access-Control-* 配置,确保没有过度授权。