CORS(跨域资源共享)配置不当与“Null”源漏洞深度剖析
1. 题目/知识点描述
CORS(跨域资源共享)是现代Web应用实现跨域请求的核心安全机制。它通过一系列HTTP响应头,允许服务器声明哪些“源”(协议+域名+端口)可以访问其资源。配置不当的CORS策略是一个经典且常见的安全漏洞,它可能导致敏感数据泄露或允许恶意网站发起跨域攻击。其中,一种特定且危险的配置错误是对“Null”源(Origin: null)的不当处理。这个知识点要求理解CORS的基本工作原理,识别常见的配置错误模式,并重点掌握由“Null”源引入的特殊攻击场景及其深度防御策略。
2. 知识背景与核心概念
在深入“Null”源漏洞前,我们先建立两个核心基础:
- 同源策略(SOP):浏览器的安全基石。它默认阻止一个源的脚本访问另一个源的资源(如通过
XMLHttpRequest或Fetch API)。这防止了恶意网站窃取用户在其他网站的数据。 - CORS机制:为了合法的跨域需求(如前后端分离),W3C制定了CORS。其核心是,当一个跨域请求(如来自
https://evil.com的脚本请求https://api.target.com/data)发起时,浏览器会自动在请求头中添加Origin: https://evil.com。服务器检查此Origin值,如果允许,则在响应头中返回Access-Control-Allow-Origin: https://evil.com(或通配符*)。浏览器看到匹配的响应头后,才会将响应内容暴露给前端JavaScript。
3. 常见CORS配置错误模式
配置错误是漏洞的根源。主要模式有:
- 过度宽松的通配符(
*):Access-Control-Allow-Origin: *。这允许任何源进行跨域访问。如果响应中包含敏感信息(如认证令牌、用户数据),且未设置Access-Control-Allow-Credentials: true,那么攻击者可以创建一个恶意页面,通过JavaScript直接读取这些数据。如果同时设置了Credentials: true,浏览器会直接阻止这种组合。 - 基于请求Origin的动态反射:服务器盲目地将请求头中的
Origin值直接反射到Access-Control-Allow-Origin响应头中。例如,请求Origin: https://evil.com,服务器响应Access-Control-Allow-Origin: https://evil.com。这相当于授予了任意来源的访问权限,是危害最大的错误之一。 - 宽松的凭证设置:
Access-Control-Allow-Credentials: true与一个过于宽松的Access-Control-Allow-Origin结合。这使得恶意网站不仅可以读取响应,还能在请求中携带目标站点的Cookies(或其他凭证),以用户的身份执行特权操作。 - 过度宽松的其他CORS头:如
Access-Control-Allow-Methods允许了危险方法(如PUT,DELETE),或Access-Control-Allow-Headers允许了自定义的敏感头。
4. “Null”源的引入与特殊性
现在,我们来聚焦“Null”源。Origin: null在以下几种特定场景中,会被浏览器自动设置:
- 请求来自本地文件(
file://协议):当HTML页面通过file://协议直接在浏览器中打开,该页面内的脚本发起的跨域请求。 - 请求源自沙箱化的
<iframe>:当<iframe>的sandbox属性未包含allow-same-origin时,其内部文档被视为一个唯一的、不透明的源,发起请求时Origin为null。 - 重定向自
data:URL:从data:URL(内联数据)发起的请求。 - 某些浏览器扩展或隐私模式下的特定请求。
关键在于:如果服务器端的CORS验证逻辑存在缺陷,特别是使用了不安全的字符串匹配或正则表达式,就可能错误地允许Origin: null。例如:
- 服务器配置为允许
https://target.com,但验证逻辑是if (origin.contains(“target.com”)) { return origin; },那么null不包含target.com,请求会被拒绝。这是安全的。 - 但是,如果服务器配置了一个允许的来源列表
[“https://app.target.com”, “https://dev.target.com”],但验证逻辑存在缺陷,比如当列表为空或匹配失败时,默认返回请求的Origin值(即反射),那么对于Origin: null的请求,就会返回Access-Control-Allow-Origin: null。 - 更常见的是,开发人员或管理员可能为了方便本地测试(
file://协议),或错误地认为null是“内部”请求,而在配置中显式地允许了null。
5. “Null”源漏洞的攻击利用
一旦服务器响应Access-Control-Allow-Origin: null,攻击者如何利用呢?关键在于攻击者能否诱导用户浏览器发出一个Origin为null的跨域请求,并且这个请求能携带受害者的凭证(Cookies)。
典型攻击链(结合沙箱化iframe):
- 攻击准备:攻击者构造一个恶意网页(托管在
https://evil.com),该页面内嵌一个沙箱化的<iframe>(sandbox属性),其src指向目标应用的某个敏感API端点(如https://api.target.com/user/profile)。 - 诱导访问:攻击者通过社交工程等方式,诱使已登录目标应用(
https://app.target.com)的用户访问这个恶意页面。 - 发起“Null”源请求:恶意页面中的JavaScript,通过
<iframe>的contentWindow,向iframe内部发起一个针对目标API的Fetch或XHR请求。由于iframe是沙箱化的(无allow-same-origin),此请求的Origin头为null。 - 漏洞触发:目标服务器错误地配置了CORS,对于
Origin: null的请求,返回了Access-Control-Allow-Origin: null。同时,如果该API端点依赖会话Cookie进行认证,并且服务器响应了Access-Control-Allow-Credentials: true,那么这个跨域请求将会自动带上用户对target.com域的Cookie。 - 数据窃取:浏览器检查CORS响应头,发现
Access-Control-Allow-Origin: null与请求的Origin: null匹配,且允许携带凭证。因此,它将API返回的包含用户敏感信息的响应暴露给恶意页面中的攻击脚本。 - 外泄数据:攻击脚本读取响应内容(如个人资料、账户信息),并将其发送到攻击者控制的服务器。
另一种利用场景(结合data: URL与重定向):
攻击者可以构造一个链接,点击后短暂跳转到一个data: URL(Origin: null),该URL中的脚本立即请求目标API,然后通过window.opener或postMessage将数据传回。
6. 深度防御与解决方案
修复“Null”源漏洞需要多层次的策略:
-
严格校验
Origin头(根本措施):- 建立白名单:在服务器端维护一个精确的、完整的可信来源(
Origin)白名单。绝对不要将null加入白名单。 - 精确匹配:使用字符串全等匹配(
===),而不是模糊匹配(如indexOf,contains, 正则表达式.*target\\.com.*)。确保请求的Origin完全等于白名单中的某一项。 - 拒绝未列出的和
null:对于不在白名单内的Origin(包括null),不设置任何Access-Control-Allow-*头,或者返回一个非CORS的响应(如普通的错误页面),让浏览器阻止前端访问响应。
- 建立白名单:在服务器端维护一个精确的、完整的可信来源(
-
避免动态反射
Origin:永远不要简单地将请求头中的Origin值直接反射回Access-Control-Allow-Origin,除非你已经通过严格的白名单校验确认它是可信的。 -
审慎使用凭证:仅在绝对必要时才设置
Access-Control-Allow-Credentials: true。当启用此选项时,Access-Control-Allow-Origin不能是通配符*,并且来源白名单必须极其严格。 -
配置正确的Vary头:在响应头中添加
Vary: Origin。这指示缓存服务器(如CDN),对于来自不同Origin的请求,应分别缓存其响应。防止攻击者通过缓存投毒,将一个允许null的CORS响应缓存后,提供给其他来源的请求。 -
限制允许的方法和头:使用
Access-Control-Allow-Methods和Access-Control-Allow-Headers仅列出应用实际需要的方法和请求头,避免过度授权。 -
进行安全测试:在安全评估和渗透测试中,将
Origin: null作为一项固定的测试用例。使用工具(如Burp Suite的“CORS Scanner”扩展)自动化地探测CORS配置漏洞,包括对null的处理。
总结
“Null”源漏洞是CORS配置错误的一个子类,但其特殊性在于攻击来源并非一个明确的恶意域名,而是浏览器特殊上下文产生的null值。防御的核心在于服务器端必须实施严格的、基于白名单的Origin校验逻辑,并明确拒绝null。作为开发者或安全人员,必须深刻理解CORS的工作细节,避免为了开发便利而引入安全缺口,从而确保跨域资源共享机制在提供功能的同时,不成为数据泄露的通道。