Web安全中的同源策略(Same-Origin Policy)与跨域安全机制详解
字数 1914 2025-11-29 03:20:48
Web安全中的同源策略(Same-Origin Policy)与跨域安全机制详解
1. 同源策略(Same-Origin Policy)的基本概念
同源策略是浏览器最核心的安全机制之一,用于限制不同源的文档或脚本之间的交互。其核心目的是防止恶意网站通过脚本窃取其他网站的数据。
- 同源的定义:两个URL的协议(Protocol)、域名(Domain)、端口(Port) 完全一致。例如:
https://example.com/app1和https://example.com/app2同源(协议、域名、端口相同)。http://example.com和https://example.com不同源(协议不同)。https://example.com和https://api.example.com不同源(域名不同)。
同源策略的限制范围:
- Cookie、LocalStorage、IndexedDB 等存储数据的访问。
- DOM 元素的读写(例如通过
iframe嵌入的页面)。 - AJAX 请求的响应(通过
XMLHttpRequest或fetch发起)。
2. 同源策略的例外场景与跨域需求
实际开发中,不同子域或端口的前后端服务需要协作,因此需安全地绕过同源策略。常见场景包括:
- 前端域名(
https://www.example.com)需调用后端API(https://api.example.com)。 - 集成第三方服务(如支付、地图)。
3. 跨域安全机制:CORS(跨域资源共享)
CORS 是W3C标准,允许服务器明确声明哪些外部源可以访问其资源。
3.1 简单请求与非简单请求
-
简单请求(满足以下所有条件):
- 方法为 GET、POST、HEAD。
- 请求头仅包含
Accept、Accept-Language、Content-Language、Content-Type(限application/x-www-form-urlencoded、multipart/form-data、text/plain)。 - 浏览器行为:自动在请求头中添加
Origin,服务器通过响应头Access-Control-Allow-Origin决定是否允许跨域。
-
非简单请求(如PUT、DELETE或携带自定义头):
- 浏览器先发送预检请求(Preflight Request)(OPTIONS方法),询问服务器是否允许实际请求。
- 服务器响应预检请求时需包含以下头部:
Access-Control-Allow-Origin: https://www.example.com // 允许的源 Access-Control-Allow-Methods: GET, POST, PUT // 允许的方法 Access-Control-Allow-Headers: X-Custom-Header // 允许的自定义头 - 通过预检后,浏览器才发送实际请求。
3.2 CORS 安全风险与防护
- 风险:若服务器配置
Access-Control-Allow-Origin: *(允许所有源),可能导致敏感数据泄露。 - 防护措施:
- 严格限制允许的源(避免使用通配符
*)。 - 对敏感请求强制要求预检机制。
- 结合认证机制(如Cookie或Token)验证请求合法性。
- 严格限制允许的源(避免使用通配符
4. 其他跨域方案与安全考量
4.1 JSONP(JSON with Padding)
- 原理:通过
<script>标签的src属性绕过同源策略(因为script标签允许跨域)。 - 风险:
- 仅支持GET请求,难以防御CSRF。
- 依赖回调函数,易遭受XSS攻击(若返回内容未过滤)。
- 适用场景:获取公开数据(如天气API),但已逐渐被CORS替代。
4.2 PostMessage API
- 原理:允许不同源的窗口之间安全地传递消息。
- 安全实践:
- 发送方指定目标窗口的源:
targetWindow.postMessage("数据", "https://trusted-site.com"); - 接收方验证消息来源:
window.addEventListener("message", (event) => { if (event.origin !== "https://expected-origin.com") return; // 处理数据 });
- 发送方指定目标窗口的源:
- 风险:若未验证
event.origin,可能导致恶意网站窃听消息。
4.3 代理服务器
- 原理:前端请求同源服务器,由服务器转发请求至目标API(服务器之间无同源限制)。
- 安全优势:隐藏后端API地址,避免直接暴露给浏览器。
5. 实战中的安全配置示例
5.1 CORS 服务器配置(Node.js/Express)
app.use((req, res, next) => {
const allowedOrigins = ["https://www.example.com", "https://app.example.com"];
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader("Access-Control-Allow-Origin", origin);
}
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
// 允许携带Cookie
res.setHeader("Access-Control-Allow-Credentials", "true");
if (req.method === "OPTIONS") return res.sendStatus(200); // 处理预检请求
next();
});
5.2 防御CSRF(跨站请求伪造)
- 同源策略不阻止跨域请求的发起,但会拦截响应。因此需额外防护:
- 使用CSRF Token(要求请求携带服务器生成的随机Token)。
- 设置Cookie的
SameSite属性(限制第三方Cookie的发送)。
6. 总结
- 同源策略是浏览器安全的基石,但需通过CORS等机制平衡功能与安全。
- 跨域方案需根据场景选择,并严格验证源、方法、头部等参数。
- 错误配置(如CORS通配符、JSONP回调过滤不严)可能导致数据泄露或XSS攻击。