一、SOP是什么?
同源策略(Same Origin Policy, SOP)是Web应用程序的一种安全模型。同源策略限制一个源上的脚本访问来自另一个源的数据,这里需要说明一点,这里的跨域请求可能不是浏览器直接拦截掉了,而是跨站请求发起了,但是返回结果被浏览器拦截了,请求实际上已经发送到了后端服务器。同源策略旨在防止网站之间的攻击。这里举个例子,如果没有同源策略,当你浏览网站A的同时也浏览了网站B,在该网站上运行的脚本代码将能访问你同时访问的网站B的数据和功能,此时如果网站A是恶意网站,如果网站B是网上银行,那么此时恶意站点就可以获取到你的个人信息或者是以你的身份在网站B上执行一些敏感操作。
同源策略中的源指的是主机,协议,端口名的一个三元组。由于同源策略有着非常严格的限制,给正常的跨域访问也带来了许多麻烦,所以人们才引入了跨域资源共享 (CORS) 这一机制,从而来可控的放宽同源策略。但是,如果网站的 CORS 策略配置和实施不当,就会产生CORS漏洞。
这里简单的说一下如何判断同源,给定一个页面,如果另一个页面使用的协议、端口、主机名与给定的页面都相同,那么我们则认为两个页面具有相同的源。例如以下 URL:
http://normal-website.com/example/example.html
访问的 URL | 允许访问? |
---|---|
http://normal-website.com/example/ | 是:相同的协议、主机名和端口 |
http://normal-website.com/example2/ | 是:相同的协议、主机名和端口 |
https://normal-website.com/example/ | 否:不同的协议和端口* |
http://en.normal-website.com/example/ | 否:不同的主机名 |
http://www.normal-website.com/example/ | 否:不同的主机名 |
http://normal-website.com:8080/example/ | 否:不同的端口** |
*https协议默认端口是443,http协议默认端口是80 **Internet Explorer 将允许此访问,因为 IE 在应用同源策略时不考虑端口号。
二、CORS是什么?
跨域资源共享 (CORS) 是一种浏览器机制,允许对位于给定域之外的资源进行受控访问。 它扩展并增加了同源策略 [SOP ] 的灵活性。
三、CORS是如何工作的?
跨域资源共享协议(Cross-origin resource sharing,CORS)使用了一套 HTTP 标头,这些标头定义了受信任的 Web 来源和相关属性,以限制源域之外的 Web 资源请求的来源。浏览器允许根据这些标头指令访问对跨域请求的响应。标头Access-Control-Allow-Origin
包含在一个网站对来自另一个网站的请求的响应中,并标识请求的允许来源。Web 浏览器将标头 Access-Control-Allow-Origin 的值与请求网站的来源进行比较,如果它们匹配,则允许访问响应。
下面这张图主要展示的是CORS的工作流程:
我这里大概描述一下上面这张图展示的过程,首先用户登录了example-b.com这个网站,然后用户又访问了example-a.com网站的某个页面,然后example-a.com网站所在的服务器将这个页面所需要加载的东西交给浏览器渲染,浏览器加载这个页面的时候发现需要加载的资源存放在example-b.com这个网站所在的服务器上面,所以浏览器通过 XMLHttpRequest 在不刷新页面的情况下请求该资源所在的url,同时浏览器会添加origin消息头,用于指示尝试提出跨域请求的域,对服务端来说,这个字段即是跨域标志。然后如果example-b.com配置了CORS,并且允许example-a.com的跨域请求,就会在返回包中返回对应的资源,再然后经过浏览器的渲染,用户请求的example-a.com上的这个页面才会完整的回显到用户看到的界面上。上图描述的就是这么一个过程,如果服务器不允许CORS,那么服务器就会返回一个拒绝响应的包,然后我们从用户角度上来看,就是浏览器报了一个错误显示资源无法正常加载。
知识补充:`XMLHttpRequest`(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。 XMLHttpRequest在 [AJAX ]编程中被大量使用。
例如,下面这个数据包,需要跨域请求时,浏览器会添加origin消息头,用于指示尝试提出跨域请求的域,对服务端来说,这个字段就是跨域标志。
GET /data HTTP/1.1
Host: example-b.com
Origin : https://example-a.com
若服务器example-b.com
返回以下响应:
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://example-a.com
当浏览器收到这个字段(Access-Control-Allow-Origin:),首先就会判断这个源(example-a.com)是否在允许范围之内,如果是,则访问者的 Web 浏览器向服务器发出跨域请求并读取响应。如果服务端返回的信息中没有这个字段,或者该源不在允许范围之内,浏览器就会拦截返回内容,不会将内容返还给调用者。默认情况下,此请求将在没有 cookie 或其他凭据的情况下发出,因此它不能用于窃取敏感的用户特定信息,例如用户个人的 [API 令牌 ]。
服务器可以使用以下标头启用凭证传输:
Access-Control-Allow-Credentials: true
当跨域请求需要访问一些私人敏感信息资源的时候,会加上cookie
GET /sensitive-personnal-data HTTP/1.1
Host: example-b.com
Origin: https://example-a.com
Cookie: sessionid=...
若服务器example-b.com
返回以下响应:
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://example-a.com
Access-Control-Allow-Credentials: true
这些标头声明允许从请求域访问(https://example-a.com
) 并且跨域请求可以包含 cookie (Access-Control-Allow-Credentials: true
) 等凭证信息,在这种情况下,若服务器的CORS配置不当,就可能会产生CORS漏洞,导致用户的敏感信息被泄露。
四、CORS漏洞是怎么产生的?
4.1CORS漏洞产生的背景:
使用标头(Access-Control-Allow-Origin:)信任单一来源很容易,如果需要信任多个来源怎么办? 该规范建议简单地指定一个以空格分隔的来源列表,例如下面这种格式:
Access-Control-Allow-Origin: http://a.example.com http://b.example.com http://c.example.com
但是,实际上没有浏览器支持这一点。
标头 Access-Control-Allow-Origin支持通配符,例如下面这种格式:
Access-Control-Allow-Origin: *
但是该标头不支持在任何其他值中使用通配符。也就是说当我们想信任某一域名的所有子域时,又不能用以下的这种格式来定义例如下面这种格式:
Access-Control-Allow-Origin: *.example.com
通配符的使用在规范中受到限制,因为不能将通配符与凭据(身份验证、cookie 或客户端证书)的跨域传输结合使用。 因此,像以下形式的跨域服务器响应是不被允许的。
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
从安全角度来看,规范之所以不允许这样做,因为这将是十分不安全的,上面的这种组合意味着将目标站点上的任何经过身份验证的内容通通都暴露给所有人。通过上面的讲述我们知道了响应凭据请求时,服务器必须指定域,并且不能在 Access-Control-Allow-Origin 中使用通配符,换句话说,使用通配符会有效地禁用 Allow-Credentials 标头。而现在的许多网站需要以完全跨域访问的方式与子域或第三方网站进行交互。
4.2CORS漏洞产生的原因:
由于上面描述的这些限制以及网站服务的需要,许多服务器选择以编程方式根据浏览器提供的 Origin 值来生成 Access-Control-Allow-Origin 标头 。一旦服务器采用这种方式,也就意味着Access-Control-Allow-Origin 标头的值是用户可以控制的,如果服务器又启用了Access-Control-Allow-Credentials: true,那么该网站就会存在泄露用户个人信息的风险。讲到这里我们也就明白了,CORS漏洞其实是使用了CORS协议的服务器配置不当所引起的。除了这种配置会导致CORS漏洞,还有一些其他的方式同样会导致这种问题。
一些支持从多个来源访问的应用程序,其服务器通过使用允许来源的白名单来实现相对安全的跨域资源共享。当服务器收到 CORS 请求时,将Origin提供的来源与白名单进行比较。如果源出现在白名单中,那么它会反映在Access-Control-Allow-Origin
标头中,以便授予访问权限。但是在白名单机制实施的时候往往会出现问题,一些网站在尝试验证是否应该信任来源时会犯经典的 URL 解析错误。 例如一些组织决定允许从其域名下的所有子域(包括现在不存在的子域)进行的访问。 还有一些允许从其他各种组织的域(包括它们的子域)进行访问。 这些规则通常通过匹配 URL 前缀或后缀,或使用正则表达式来实现。但是在这些方法实施的过程中,极可能导致授予意外的外部域,从而产生CORS漏洞,例如下面的这些情况:
例如,假设一个应用程序授予对以下结尾的所有域的访问权限:
normal-website.com
那么攻击者可能能够通过注册一些域,从而来获得访问权限:
hackers.normal-website.com
又或者,应用程序授予包含以下域的所有域的访问权限:
normal-website.com
攻击者可能通过注册一些域然后获得访问权限:
normal-website.com.evil-user.net
事实证明,还有另一种方式,但需要满足一定的条件才行,这种利用方法借助了浏览器解析特性并且配合使用了配置了通配符的DNS记录来完成,由于这种利用方法属于比较高级的方法,还需要许多的相关知识,我这里只是提一下,对这种利用方法比较感兴趣的师傅,也可以在我文末给到的链接中找到相关的文章进行学习。
在CORS规范中,Origin 标头的规范支持null
值 . 在各种异常情况下的 Origin 标头中: 浏览器可能会发送null
跨域重定向。
来自序列化数据的请求。
请求使用
file:
协议。沙盒化的跨域请求。
某些应用程序可能会将origin 的值设置成null用来支持应用程序的本地开发或者测试。但是当应用程序正式上线后由于种种原因,null值仍然在白名单中,在这种情况下,攻击者可以使用各种技巧来生成包含Origin :null的跨域请求,如果服务器又设置了Access-Control-Allow-Credentials: true 那么CORS漏洞也就因此产生。
假设一个应用程序接收到以下跨域请求:
GET /sensitive-victim-data
Host: vulnerable-website.com
Origin: null
服务器响应:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
那么也就说明这里也是存在CORS漏洞的。
简单总结
本篇文章主要简单讲述了,SOP、CORS是什么,CORS的工作流程,CORS漏洞产生的背景及原因。由于文章篇幅的原因,关于CORS漏洞的挖掘、具体利用方法、以及如何修复CORS漏洞或者如何避免产生CORS漏洞的内容我将放在下一篇文章中来描述