Web安全之同源策略与跨域解决方案进阶
字数 1929 2025-11-06 12:41:20
Web安全之同源策略与跨域解决方案进阶
一、同源策略的本质
同源策略是浏览器最核心的安全机制之一,它限制一个源的文档或脚本如何与另一个源的资源交互。
- 同源的定义:协议、域名、端口完全相同。例如:
https://a.com/index.html与https://a.com/api同源(协议、域名、端口一致)。https://a.com与http://a.com不同源(协议不同)。
- 限制范围:
- Cookie/LocalStorage 访问
- DOM 操作(如 iframe 嵌套)
- AJAX 请求(实际可发送,但响应被浏览器拦截)
二、跨域解决方案的底层原理
1. JSONP(JSON with Padding)
原理:利用 <script> 标签不受同源策略限制的特性,通过动态创建脚本标签发起 GET 请求。
步骤:
- 前端定义全局回调函数:
function handleResponse(data) { console.log(data); } - 动态添加
<script>标签:const script = document.createElement('script'); script.src = 'https://api.example.com/data?callback=handleResponse'; document.body.appendChild(script); - 服务端返回回调函数包裹的数据:
handleResponse({ "status": "success", "data": ... });
缺点:仅支持 GET 请求,缺乏错误处理机制。
2. CORS(跨域资源共享)
原理:服务端通过设置 HTTP 响应头显式允许某些源的请求。
- 简单请求(直接触发 CORS):
- 方法为 GET/POST/HEAD,Content-Type 为
application/x-www-form-urlencoded、multipart/form-data或text/plain。 - 浏览器自动在请求头添加
Origin: https://a.com,服务端需返回Access-Control-Allow-Origin: https://a.com(或*)。
- 方法为 GET/POST/HEAD,Content-Type 为
- 预检请求(需先发送 OPTIONS 请求):
- 触发条件:自定义头(如
Authorization)、非简单 Content-Type(如application/json)。 - 浏览器先发送 OPTIONS 请求,服务端需响应:
Access-Control-Allow-Origin: https://a.com Access-Control-Allow-Methods: POST, GET Access-Control-Allow-Headers: Content-Type
- 触发条件:自定义头(如
- 携带凭证(如 Cookie):
- 前端设置
withCredentials: true,服务端需指定Access-Control-Allow-Origin为具体源(不能为*),并返回Access-Control-Allow-Credentials: true。
- 前端设置
3. 代理服务器
原理:将跨域请求转发至同源的服务端,由服务端代为请求目标接口。
- 开发环境:Webpack DevServer 配置
proxy:devServer: { proxy: { '/api': { target: 'https://api.example.com', changeOrigin: true // 修改请求头中的 Origin 为目标地址 } } } - 生产环境:通过 Nginx 反向代理:
location /api/ { proxy_pass https://api.example.com/; proxy_set_header Host $host; }
4. postMessage
原理:允许不同源的窗口间通过消息事件通信。
// 发送方(https://a.com)
iframe.contentWindow.postMessage('Hello', 'https://b.com');
// 接收方(https://b.com)
window.addEventListener('message', (event) => {
if (event.origin !== 'https://a.com') return;
console.log(event.data); // 'Hello'
});
5. document.domain(适用于子域跨域)
原理:将同一主域下的子域页面设置为相同域名。
- 限制:仅适用于
a.example.com与b.example.com之间的跨域。 - 代码:
// 在两个页面中均设置 document.domain = 'example.com';
三、方案对比与适用场景
| 方案 | 适用场景 | 优势 | 缺陷 |
|---|---|---|---|
| JSONP | 老旧浏览器兼容、简单 GET 请求 | 兼容性好 | 安全性低、仅支持 GET |
| CORS | 现代浏览器、需灵活控制请求方法 | 前端无需改动、支持多种请求类型 | 需服务端配合 |
| 代理服务器 | 开发环境调试、避免服务端改动 | 前端无感知、可缓存请求 | 生产环境需部署代理中间件 |
| postMessage | 跨窗口通信(如微前端) | 安全可控、支持复杂数据 | 需主动监听消息事件 |
四、安全注意事项
- CORS 的
Access-Control-Allow-Origin: *需谨慎使用,避免敏感数据泄露。 - JSONP 的风险:可能被恶意注入脚本,需校验数据来源。
- 代理服务器需防范 SSRF 攻击(服务端请求伪造)。
通过理解同源策略的约束机制及各类跨域方案的底层原理,可根据实际场景选择最合适的安全解决方案。