阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 同源策略与跨域安全

同源策略与跨域安全

作者:陈川 阅读数:61583人阅读 分类: HTML

同源策略的基本概念

同源策略是浏览器实施的一种重要安全机制,它限制了一个源的文档或脚本如何与另一个源的资源进行交互。所谓"同源",指的是协议、域名和端口号完全相同。例如:

  • https://example.com/page1https://example.com/page2 是同源
  • https://example.comhttp://example.com 不同源(协议不同)
  • https://example.comhttps://sub.example.com 不同源(域名不同)
  • https://example.comhttps://example.com:8080 不同源(端口不同)

同源策略主要影响以下操作:

  1. AJAX请求
  2. Web Storage和IndexedDB访问
  3. Cookie读取
  4. DOM访问(iframe间通信)
// 尝试跨域访问会触发同源策略限制
fetch('https://api.other-site.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('跨域请求被阻止:', error));

跨域资源共享(CORS)

CORS是现代浏览器支持的标准机制,允许服务器声明哪些外部源可以访问其资源。当需要跨域请求时,浏览器会自动发送一个预检请求(OPTIONS)来检查服务器是否允许实际请求。

简单请求与预检请求

简单请求需满足以下条件:

  • 使用GET、HEAD或POST方法
  • 仅包含安全的首部字段(Accept、Accept-Language等)
  • Content-Type为application/x-www-form-urlencoded、multipart/form-data或text/plain
// 简单请求示例
fetch('https://api.example.com/data', {
  method: 'GET',
  headers: {
    'Content-Type': 'text/plain'
  }
});

非简单请求会触发预检:

// 会触发预检的请求
fetch('https://api.example.com/data', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'value'
  },
  body: JSON.stringify({key: 'value'})
});

服务器端CORS配置

Node.js Express示例:

const express = require('express');
const app = express();

// 基本CORS配置
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://trusted-site.com');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', 'true');
  
  // 处理预检请求
  if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }
  next();
});

JSONP跨域技术

在CORS出现前,JSONP是常用的跨域解决方案。它利用<script>标签不受同源策略限制的特性。

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);

服务器需要返回包装在回调函数中的JSON数据:

// 服务器响应
handleResponse({
  "name": "示例数据",
  "value": 42
});

JSONP的局限性:

  • 仅支持GET请求
  • 缺乏错误处理机制
  • 存在安全风险(XSS漏洞)

postMessage跨文档通信

对于不同源的iframe或窗口间通信,可以使用postMessage API。

// 发送消息到iframe
const iframe = document.getElementById('my-iframe');
iframe.contentWindow.postMessage({
  type: 'data_update',
  payload: { key: 'value' }
}, 'https://target-origin.com');

// 接收消息
window.addEventListener('message', (event) => {
  // 验证来源
  if (event.origin !== 'https://trusted-origin.com') return;
  
  console.log('收到消息:', event.data);
});

跨域安全最佳实践

  1. 严格设置CORS头

    • 避免使用Access-Control-Allow-Origin: *
    • 明确指定允许的方法和头
  2. CSRF防护

    • 使用SameSite Cookie属性
    • 实现CSRF令牌
<!-- 表单中包含CSRF令牌 -->
<form action="/transfer" method="POST">
  <input type="hidden" name="_csrf" value="token-value">
  <!-- 其他表单字段 -->
</form>
  1. 内容安全策略(CSP)
    • 限制脚本来源
    • 防止XSS攻击
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' https://trusted-cdn.com">
  1. 避免敏感信息暴露
    • 不要在前端代码中硬编码API密钥
    • 使用环境变量或后端代理

WebSocket跨域安全

WebSocket协议本身不受同源策略限制,但仍需注意安全:

const socket = new WebSocket('wss://api.example.com/ws');

// 服务器应验证Origin头
socket.onopen = () => {
  socket.send(JSON.stringify({ action: 'subscribe' }));
};

socket.onmessage = (event) => {
  console.log('收到消息:', event.data);
};

现代跨域技术

  1. 代理服务器
    • 前端请求同源服务器
    • 服务器转发请求到目标API
// 前端请求
fetch('/api/proxy', {
  method: 'POST',
  body: JSON.stringify({
    url: 'https://target-api.com/endpoint',
    method: 'GET'
  })
});
  1. 反向代理
    • 使用Nginx配置
location /api/ {
  proxy_pass https://target-api.com/;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
}
  1. 跨域资源共享的扩展
    • 跨域资源共享策略(CORP)
    • 跨域隔离状态
Cross-Origin-Resource-Policy: same-site

常见跨域场景解决方案

  1. 跨域Cookie
    • 设置withCredentialsAccess-Control-Allow-Credentials
fetch('https://api.example.com/auth', {
  credentials: 'include'
});
  1. 跨域图片
    • 使用crossOrigin属性
<img src="https://other-site.com/image.jpg" crossOrigin="anonymous">
  1. 字体跨域
    • 配置正确的CORS头
@font-face {
  font-family: 'CustomFont';
  src: url('https://other-site.com/font.woff2') format('woff2');
  font-display: swap;
}

浏览器安全沙箱与跨域

现代浏览器实现了严格的沙箱机制,进一步增强了跨域安全:

  1. 站点隔离

    • 每个站点在独立进程中运行
    • 防止Spectre等侧信道攻击
  2. 跨域策略文件

    • crossorigin.xml定义允许的跨域访问
    • Flash时代遗留,现代Web较少使用
  3. CORB(跨域读取阻止)

    • 浏览器阻止某些类型的跨域响应
    • 如JSON、HTML、XML等敏感数据类型

性能优化与跨域

跨域请求可能影响性能,优化策略包括:

  1. 预加载

    <link rel="preconnect" href="https://api.example.com">
    <link rel="dns-prefetch" href="https://cdn.example.com">
    
  2. CDN加速

    • 使用同一CDN域名提供静态资源
    • 减少DNS查询和TCP握手
  3. HTTP/2优化

    • 多路复用减少连接开销
    • 头部压缩降低传输量

新兴标准与未来趋势

  1. WebAssembly跨域

    • 严格的模块安全限制
    • 需要CORS和CORB保护
  2. Portals API

    • 允许嵌入跨源内容
    • 提供更好的用户体验
  3. SharedArrayBuffer

    • 需要跨域隔离状态
    • 高精度计时器限制
// 检查跨域隔离状态
if (crossOriginIsolated) {
  // 可以使用SharedArrayBuffer等高级特性
  const buffer = new SharedArrayBuffer(1024);
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌