跨域资源共享(CORS)
1. 跨域资源共享(CORS)
是一种机制,用于放宽浏览器的同源策略,使得一个域可以访问另一个域的数据。随着互联网应用的日益复杂,CORS成为解决跨域问题的标准方法之一。
2. 浏览器的同源策略
浏览器为了安全起见,遵循同源策略(Same-origin policy),即只有当请求的源(协议、域名、端口)与资源所在的源完全相同时,才允许进行交互。这种策略有效地防止了某些类型的攻击,但也限制了跨域数据的访问。
示例:
假设你有一个网站 example.com
并且想要请求来自 data.example.org
的资源,如果没有CORS的支持,浏览器会阻止这个请求。
3. CORS基本原理
CORS通过HTTP头部信息来控制跨域访问的权限,允许服务器指定哪些源可以访问其资源。
-
简单请求:当请求符合以下条件时,被视为简单请求:
- 方法为
GET
、HEAD
或POST
; Content-Type
头部的值仅限于application/x-www-form-urlencoded
、multipart/form-data
或text/plain
。
- 方法为
-
预检请求:对于不符合简单请求条件的请求,浏览器会自动发送一个预检请求(OPTIONS方法),以询问服务器是否允许实际请求。预检请求会包含:
Access-Control-Request-Method
头部,指示实际请求的方法;Access-Control-Request-Headers
头部,列出实际请求中可能会包含的自定义头部。
示例:
一个简单的GET请求可以直接发送到服务器,而一个包含自定义头部的POST请求则会先发送一个预检请求。
// 客户端发起预检请求
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'XYZ'
},
body: JSON.stringify({key: 'value'})
});
// 服务器收到预检请求
OPTIONS /data HTTP/1.1
Host: api.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, x-custom-header
Origin: http://example.com
...
4. CORS的实现
- 服务端配置:
- 在服务端响应中添加
Access-Control-Allow-Origin
头部来指定允许访问的源。 - 可能还需要添加其他头部,如
Access-Control-Allow-Methods
和Access-Control-Allow-Headers
。
- 在服务端响应中添加
示例:
在Node.js Express中配置CORS中间件。
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/data', function(req, res) {
res.json({message: 'Hello from server!'});
});
app.listen(3000);
- 客户端示例:
- 使用JavaScript发起跨域请求,例如使用
fetch
API 或XMLHttpRequest
。 - 确保请求遵守CORS规则。
- 使用JavaScript发起跨域请求,例如使用
示例:
使用 fetch
发起一个GET请求。
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
5. CORS的最佳实践
- 使用严格但必要的
Access-Control-Allow-Origin
配置。 - 对于预检请求,合理设置
Access-Control-Allow-Methods
和Access-Control-Allow-Headers
。 - 考虑使用
Access-Control-Max-Age
减少预检请求频率。
示例:
在服务端响应中设置CORS头部。
app.options('/data', function(req, res) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
res.status(200).send('');
});
6. CORS的安全考量
- 确保
Access-Control-Allow-Origin
不被滥用,避免安全风险。 - 限制敏感操作的跨域访问。
示例:
限制允许的源,并禁用凭证传输。
app.use(cors({
origin: 'http://example.com',
credentials: false
}));