浅析CORS跨域漏洞与JSONP劫持

本文涉及的产品
.cn 域名,1个 12个月
简介: 浅析CORS跨域漏洞与JSONP劫持

文章目录
前言
同源策略
AJAX技术
CORS跨域
跨域流程
攻击流程
漏洞验证
靶场实例
检测方法
结合XSS
漏洞扫描
防护方案
JSONP劫持
利用过程
靶场实例
漏洞挖掘
防护方案
前言
CORS 全称为 Cross-Origin Resource Sharing ,即跨域资源共享,用于绕过SOP(同源策略)来实现跨域资源访问的一种技术。而 CORS 漏洞则是利用 CORS 技术窃取用户敏感数据。

JSONP 全称是 JSON with Padding ,是基于 JSON 格式的为解决跨域请求资源而产生的解决方案。JSONP 实现的基本原理是利用了 HTML 里 元素标签,远程调用 JSON 文件来实现数据传递。当某网站通过 JSONP 的方式来跨域(一般为子域)传递用户认证后的敏感信息时,攻击者可以构造恶意的 JSONP 调用页面,诱导被攻击者访问来达到截取用户敏感信息的目的。

CORS 漏洞、 JSONP 劫持实际上都属于 CSRF 跨站请求伪造漏洞,尽管二者已经出现了很多年,但由于部分厂商对此不够重视导致其仍在不断发展和扩散。

同源策略
对 CORS 的介绍要从浏览器的同源策略开始说起,SOP 全称为 Same Origin Policy,即同源策略。该策略是浏览器的一个安全基石,同源策略规定:不同域的客户端脚本在没有明确授权的情况下,不能读写对方的资源。

简单来说同源策略就是浏览器会阻止一个源与另一个源的资源交互。可以试想一下,如果没有同源策略,当你访问一个正常网站的时候又无意间打开了另一个恶意网站,恶意网站会从你刚刚访问的正常网站上窃取你全部的信息。所谓同源是指 域名,协议,端口相同。如何判断是否是同源,可以查看该表:

AJAX技术
跨域问题是针对使用XMLHttpRequest 技术构建的复杂的、动态的网页的编程实践技术—— AJAX 的,HTML 本身没有跨域问题。

AJAX 全称 Asynchronous JavaScript + XML,即异步 JavaScript 和 XML。AJAX 本身不是一种新技术,而是用来描述一种使用现有技术集合/标准的新方法,包括:HTML or XHTML、Cascading Style Sheets、JavaScript、The Document Object Model、XML、XSLT 以及 XMLHttpRequest object。AJAX 允许只更新一个 HTML 页面的部分 DOM,而无须重新加载整个页面, 网页应用能够快速地将增量更新呈现在用户界面上,而不需要重新加载整个页面。这使得程序能够更快地回应用户的操作。

【注意】尽管X在 Ajax 中代表 XML, 但由于 JSON 的许多优势,比如更加轻量以及作为 Javascript 的一部分,目前 JSON 的使用比 XML 更加普遍。JSON 和 XML 都被用于在 Ajax 模型中打包信息。

当我们使用 AJAX 技术发送 XMLHttpRequest 请求的时候,如果请求的是别的域 (主机域名、端口) 不同时,那么就会产生跨域问题(受同源策略影响,客户端将无法获取服务端返回的数据,除非使用 COERS 跨域资源共享技术)。值得注意的是:跨域的问题是发生在 XMLHttpRequest 请求的,也就是说,不是 XMLHttpRequest 请求是不会有跨域问题的。举个很简单的例子:在编写网页的时候,,在 CORS 跨域资源共享技术的作用下,URL 不是本域的还是可以正常获取该图片的。

CORS跨域
SOP 浏览器同源策略是一个很好的策略,在 SOP 被提出之后,大家都默默地遵守着这个规定,但随着WEB应用的发展,有些网站由于自身业务的需求,需要实现一些跨域的功能能够让不同域的页面之间能够相互访问各自页面的内容。常见需要跨域的业务场景如下:

比如后端开发完一部分业务代码后,提供接口给前端用,在前后端分离的模式下,前后端的域名是不一致的,此时就会发生跨域访问的问题;
程序员在本地做开发,本地的文件夹并不是在一个域下面,当一个文件需要发送 ajax 请求,请求另外一个页面的内容的时候,就会跨域;
电商网站想通过用户浏览器加载第三方快递网站的物流信息;
子站域名希望调用主站域名的用户资料接口,并将数据显示出来。
为了实现这个跨域需求,聪明的程序员想到了一种编码技术 JSONP,该技术利用从客户端传入的 json 格式的返回值,在服务器端调用该接口处事先以定义函数的方式定义好 json 格式里参数值,并加载 script 标签调用该函数实现跨域。 JSONP 虽然好,但它并非是在协议层面解决跨域问题,所以出现了很多安全问题。

为了能更安全的进行跨域资源访问,CORS 诞生了。CORS 是 H5 提供的一种机制,WEB 应用程序可以通过在 HTTP 报文中增加特定字段来告诉浏览器,哪些不同来源的服务器是有权访问本站资源。CORS 是 H5 提供的一种机制,WEB 应用程序可以通过在 HTTP 报文中增加特定字段来告诉浏览器,哪些不同来源的服务器是有权访问本站资源。

跨域流程
浏览器将CORS请求分成两类:简单请求(simple request)和 非简单请求(not-so-simple request)。只要同时满足以下两个条件就属于简单请求否则属于非简单请求(主要通过请求方法进行判断):

请求方法是(HEAD,GET,POST)三种之一;
HTTP的头信息不超出(Accept,Accept-Language,Content-Language,Lat-Event-ID,Content-Type)这几种字段。
CORS跨域——简单请求的流程

对于简单请求,大致流程是浏览器发现这一次向服务器提交的请求是简单请求,所以自动在头信息中增加了一个Origin的字段,用来表示这次的请求来自哪个域。当服务器接收到请求后发现Origin字段指定的域名在许可范围内,服务器会在响应包中增加三个与CORS相关的字段:

Access-Control-Allow-Origin:该字段是必须存在的,它的值可能是 Origin 字段的值或者是一个通配符“*”,表示可以接受任意域名的请求,当然大部分服务器如果配置了通配符的话,信息泄露的风险骤然加大;
Access-Control-Allow-Credentials:字段不是必选字段,它的值是一个布尔值且只能设置为 true,表示服务器允许浏览器将 cookie 包含在请求中,否则就不添加此字段。但需要注意的是,如果要发送 cookie,Access-Control-Allow-Origin 就不能设为星号,必须明确指定与请求网页一致的域名,同时Cookie依然遵循同源策略。
Access-Control-Expose-Headers:该字段主要是指定想要获取 XMLHttpRequest 对象中 getResponseHeader() 方法的其他服务器字段。
具体的 CORS 简单跨域请求流程如下:

CORS跨域——非简单请求的流程

所谓非简单请求就是那种对服务器提出特殊要求的请求,例如请求方法为 PUT 或 DELETE。非简单的 CORS 请求会在正式通信之前,增加一次 HTTP 查询请求,称之为 “预检请求” 。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单里以及可以使用哪些 HTTP 动词和头信息字段。只有获得了肯定响应,浏览器才会正式发出 XMLHttpRequest 请求否则就报错。这种请求的好处是对传统的没有 CORS 支持的服务器减小压力,给服务器一个提前拒绝的机会。

具体流程如上图所示,当构造请求包的方法是 PUT 或 DELETE 并传给浏览器时,浏览器发现此请求是非简单请求所以浏览器构造一个预检请求包,请求头是 OPTIONS,并携带三个关键字段:Origin、Access-Control-Request-Method、Access-Control-Request-Headers。其中 Access-Control-Request-Method 表示浏览器的 CORS 请求会用到哪些HTTP方法, Access-Control-Request-Headers 表示浏览器 CORS 请求会额外发送的头信息字段。服务器收到预检请求后,检查了三个核心字段以后如果确定允许跨域请求,会返回一个正常的 HTTP 回应,并携带传入的 CORS 头信息。如果服务器否定请求,虽然也会返回一个正常的 HTTP 回应但是没有任何 CORS 相关的头信息字段,或明确表示请求不符合条件。浏览器根据预请求的返回结果决定接下来是进行简单请求还是拒绝请求。

攻击流程
CORS 使用检查请求头的相关字段和服务端的规则进行对比,来选择是否允许跨域。但凡是需要配置规则的程序,避免不了会出现一些意外,就像很多资深程序员有时也会写不出恰当的正则一样,当服务端配置的规则不够合理,导致非同域的资源可以互相访问,例如Access-Control-Allow-Origin: *。 CORS 反而使同源策略的保护机制土崩瓦解。因此,CORS 漏洞的成因很明显,就是服务端配置的规则不当所导致的。

CORS 跨域漏洞的攻击流程如上图所示:

假设用户登陆一个含有 CORS 配置网站 vuln.com,同时又访问了攻击者提供的一个链接 evil.com。
evil.com 的网站向 vuln.com 这个网站发起请求获取敏感数据,浏览器能否接收信息取决于 vuln.com 的配置。
如果 vuln.com 配置了 Access-Control-Allow-Origin 头且为预期,那么允许接收,否则浏览器会因为同源策略而不接收。
漏洞验证
1、这是一个正常的GET请求包:

其正常响应包为:

2、我们现在在该请求包上面添加一个origin参数:

3、返回包的数据中出现了对应的 CORS 响应头:

其中Access-Control-Allow-Origin指是允许访问的源,Access-Control-Allow-Credentials指的是允许带上 cookie 访问资源,这样我们就可以通过 POST 获取到访问者的 cookie 信息。

靶场实例
以 BWAPP 靶场 Low 级别的 CORS 漏洞环境作为演示案例:

1、点击 secret 跳转到如下页面,藏着 Neo 的秘密:

2、现在攻击者的目的是盗取该页面里面的 sercet 密码内容,查看请求这个页面时的HTTP响应头,从Access-Control-Allow-Origin:* 头可以看出服务器配置了 CORS,且所有的源服务器都可以加载这个页面上的资源:

3、攻击者可以直接发送一个自己构造的页面链接给用户,当用户点击后,攻击页面使用 ajax 就可以直接读取另一个 BWAPP 靶场网站的目标网页敏感信息,攻击页面 test.html 源码如下:

<!DOCTYPE html>






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
4、此处将该页面放在本地 PhpStudy 搭建的服务下,并在浏览器进行访问,将成功跨域发送资源请求并返回想要的敏感信息(控制台打印):

检测方法
如何在平常测试中检查 CORS 跨域漏洞?

CORS 漏洞主要看当我们发起的请求中带有 Origin 头部字段时,服务器的返回包带有 CORS 的相关字段并且允许 Origin 的域访问。

一般测试WEB漏洞都会用上BurpSuite,而BurpSuite可以实现帮助我们检测这个漏洞。

1、首先是自动在 HTTP 请求包中加上 Origin 的头部字段,打开BurpSuite,选择 Proxy 模块中的 Options 选项,找到 Match and Replace 这一栏,勾选 Request header 将空替换为 Origin:foo.example.org 的Enable框:
2、然后我们就可以开始去访问我们认为有漏洞的网站,访问足够多后在 BurpSuite 的 Proxy 模块下的 HTTP history 来筛选带有 CORS 头部的值:

我们的条件可以是如下:

Access-Control-Allow-Origin: foo.example.org
Access-Control-Allow-Credentials: true
1
2
3、检测效果如下:

【注意】这里要注意的是,我们也可以测试下带有 CORS 字段的网站是否有 CORS 漏洞,如果服务器响应包的请求头是以下几种情况则可存在 CORS 漏洞:

实锤存在: 有且仅有如下请求头
Access-Control-Allow-Origin: *
实锤存在:同时存在如下两个请求头
Access-Control-Allow-Origin: https://attacker.com
Access-Control-Allow-Credentials: true
可能存在:同时存在如下两个请求头
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
但是如果是如下组合,则绝对没有漏洞,因为该配置下浏览器会自动阻止:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
1
2
结合XSS
有时候 CORS 配置了信任自身的任意子域,那么如果一个子域存在 XSS 漏洞就可以通过这个漏洞去读取其他子域的资源,类似的场景还有比如 HTTPS 域信任 HTTP 域等。

漏洞扫描
可以使用 Xray 联动 BurpSuite 进行扫描,如下是 Xray 扫出来的一次 CORS:
同时 github上 提供了一个关于扫描 CORS 配置漏洞的脚本,https://github.com/chenjj/CORScanner。

root@kali:~/Desktop/CORScanner# python cors_scan.py -h
usage: cors_scan.py [-h] [-u URL] [-i INPUT] [-t THREADS] [-o OUTPUT]
[-v [VERBOSE]] [-d [HEADERS [HEADERS ...]]]

OPTIONS:
-h, --help show this help message and exit
-u URL, --url URL URL/domain to check it's CORS policy
-i INPUT, --input INPUT
URL/domain list file to check their CORS policy
-t THREADS, --threads THREADS
Number of threads to use for CORS scan
-o OUTPUT, --output OUTPUT
Save the results to text file
-v [VERBOSE], --verbose [VERBOSE]
Enable Verbosity and display results in realtime
-d [HEADERS [HEADERS ...]], --headers [HEADERS [HEADERS ...]]
Add headers to the request.

Example: python cors_scan.py -u google.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
我们将检测的域名写在一个记事本里,然后使用-i参数去进行批量扫描。

防护方案
关闭不必要开启的CORS;
白名单限制:定义“源”的白名单,避免使用正则表达式,不要配置 Access-Control-Allow-Origin 为通配符 * 或 null ,严格效验来自请求数据包中的 Origin 的值;
仅允许使用安全协议,避免中间人攻击;
尽可能的返回 Vary: Origin 头部,以避免攻击者利用浏览器缓存进行攻击;
避免将 Access-Control-Allow-Credentials 标头设置为默认值 true ,跨域请求若不存在必要的凭证数据,则根据实际情况将其设置为 false;
限制跨域请求允许的方法,Access-Control-Allow-Methods 最大限度地减少所涉及的方法,降低风险;
限制浏览器缓存期限:建议通过 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 头部,限制浏览器缓存信息的时间。通过配置 Access-Control-Max-Age 标头来完成,该头部接收时间数作为输入,该数字是浏览器保存缓存的时间。配置相对较低的值,确保浏览器在短时间内可以更新策略;
仅在接收到跨域请求时才配置有关于跨域的头部,并确保跨域请求是合法的源,以减少攻击者恶意利用的可能性。
JSONP劫持
JSONP 全称是 JSON with Padding ,是基于 JSON 格式的为解决跨域请求资源而产生的解决方案,它是 json 的一种“使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据。

JSONP 实现的基本原理是利用了 HTML 里 元素标签,远程调用 JSON 文件来实现数据传递。当某网站通过 JSONP 的方式来跨域(一般为子域)传递用户认证后的敏感信息时,攻击者可以构造恶意的 JSONP 调用页面,诱导被攻击者访问来达到截取用户敏感信息的目的。

利用过程
JSONP 劫持漏洞的利用过程如下:

用户在网站B 注册并登录,网站B 包含了用户的id,name,email等信息;
用户通过浏览器向网站A发出URL请求;
网站A向用户返回响应页面,响应页面中注册了 JavaScript 的回调函数和向网站B请求的 script 标签,示例代码如下:


1
2
3
4
5
6
7
用户收到响应,解析 JS 代码,将回调函数作为参数向网站B发出请求;
网站 B 接收到请求后,解析请求的 URL,以 JSON 格式生成请求需要的数据,将封装的包含用户信息的 JSON 数据作为回调函数的参数返回给浏览器,网站B返回的数据实例如下:
Callback({"id":1,"name":"test","email":"test@test.com"})
1
网站B数据返回后,浏览器则自动执行 Callback 函数对步骤4返回的 JSON 格式数据进行处理,通过 alert 弹窗展示了用户在网站B的注册信息。另外也可将 JSON 数据回传到网站A的服务器,这样网站A利用网站B的JSONP漏洞便获取到了用户在网站B注册的信息。
JSONP 漏洞利用过程示意图:

JSONP 劫持是一种敏感信息泄露的漏洞,经过攻击者巧妙而持久地利用,会对企业和用户造成巨大的危害。攻击者通过巧妙设计一个网站, 网站中包含其他网站的 JSONP 劫持漏洞利用代码 ,将链接通过邮件等形式推送给受害人, 如果受害者点击了链接,则攻击者便可以获取受害者的个人的信息,如邮箱、姓名、手机等信息, 这些信息可以被违法犯罪分子用作“精准诈骗”。对方掌握的个人信息越多,越容易取得受害人的信任,诈骗活动越容易成功,给受害人带来的财产损失以及社会危害也就越大。

靶场实例
下面以 DoraBox 靶场的 JSONP 劫持漏洞为演示案例:
访问 JSONP 靶场环境页面:
其服务端源码如下:

<?php
include "../class/function.class.php";
$reqMethod = "GET";
$reqValue = "callback";
$p = new Func($reqMethod, $reqValue);
$info = array('username' => 'Vulkey_Chen', 'mobilephone' => '13188888888', 'email' => 'admin@gh0st.cn', 'address' => '中华人民共和国', '**' => 'Cool Man');
if(!@$_GET['callback']){
echo $p -> con_function('json_encode',$info);
}else{
$callback = htmlspecialchars($_GET['callback']);
echo "{$callback}(" . $p -> con_function('json_encode',$info) . ")";
}
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
重点关注:

if(!@$_GET['callback']){
echo $p -> con_function('json_encode',$info);
}else{
$callback = htmlspecialchars($_GET['callback']);
echo "{$callback}(" . $p -> con_function('json_encode',$info) . ")";
}
1
2
3
4
5
6
这里首先以 get 形式接收到 callback 的值,如果 callback 为空,则忽略警告输出 info 的 json 格式数据:如果 callback 值不为空,则对这个值做一个过滤后输出,然后后面还是输出 json 格式的 info 的值:
从这段代码我们可以看到,callback 的值是可以动态输出的,如果我们现在拿到了一个以 jsonp 方式传输用户认证后数据的网站,我们就可以构造出一个恶意的 jsonp 调用页面,然后诱使用户访问我们的页面,从而达到一个截取用户信息的目的。

<!DOCTYPE html>










1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
将上面的 jsonp_attack.html 页面放在本地 phpstudy 搭建的服务网站根目录下,浏览器进行访问,成功获得敏感信息(手机号码):
简单修改下恶意网页链接的代码,也可以直接弹窗返回全部信息:
看下访问效果:

漏洞挖掘
1、搜索引擎 Hacking 语法——site:target.com inurl:?callback:
2、浏览器-调试-搜索关键字(json/jsonp/callback):

防护方案
1、严格安全的实现 CSRF 方式调用 JSON 文件:限制 Referer 、部署一次性 Token 等。

2、严格安装 JSON 格式标准输出 Content-Type 及编码( Content-Type : application/json; charset=utf-8 )。

3、严格过滤 callback 函数名及 JSON 里数据的输出。

4、严格限制对 JSONP 输出 callback 函数名的长度(如防御上面 flash 输出的方法)。

5、其他一些比较“猥琐”的方法:如在 Callback 输出之前加入其他字符(如:/**/、回车换行)这样不影响 JSON 文件加载,又能一定程度预防其他文件格式的输出。还比如 Gmail 早起使用 AJAX 的方式获取 JSON ,听过在输出 JSON 之前加入 while(1) ;这样的代码来防止 JS 远程调用。
————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_39190897/article/details/113769462

目录
相关文章
|
6天前
|
开发框架 中间件 Java
如何处理跨域资源共享(CORS)的 OPTIONS 请求?
处理 CORS 的 OPTIONS 请求的关键是正确设置响应头,以告知浏览器是否允许跨域请求以及允许的具体条件。根据所使用的服务器端技术和框架,可以选择相应的方法来实现对 OPTIONS 请求的处理,从而确保跨域资源共享的正常进行。
|
6天前
|
JavaScript 前端开发 API
跨域资源共享(CORS)的工作原理是什么?
跨域资源共享(CORS)通过浏览器和服务器之间的这种交互机制,在保证安全性的前提下,实现了跨域资源的访问,使得不同源的网页能够合法地获取和共享服务器端的资源,为现代Web应用的开发提供了更大的灵活性和扩展性。
|
20天前
|
JSON 前端开发 安全
CORS 是什么?它是如何解决跨域问题的?
【10月更文挑战第20天】CORS 是一种通过服务器端配置和浏览器端协商来解决跨域问题的机制。它为跨域资源共享提供了一种规范和有效的方法,使得前端开发人员能够更加方便地进行跨域数据交互。
|
1月前
|
缓存 前端开发 应用服务中间件
CORS跨域+Nginx配置、Apache配置
CORS跨域+Nginx配置、Apache配置
121 7
|
2月前
|
安全
CORS 跨域资源共享的实现原理
CORS 跨域资源共享的实现原理
|
3月前
|
Web App开发 JSON 数据格式
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
|
3月前
|
API
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
|
3月前
|
安全 开发者 UED
|
5月前
|
前端开发 安全 JavaScript
Spring Boot2 系列教程(十四)CORS 解决跨域问题
Spring Boot2 系列教程(十四)CORS 解决跨域问题
|
3月前
|
安全 前端开发 Java
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例
在Web安全上下文中,源(Origin)是指一个URL的协议、域名和端口号的组合。这三个部分共同定义了资源的来源,浏览器会根据这些信息来判断两个资源是否属于同一源。例如,https://www.example.com:443和http://www.example.com虽然域名相同,但由于协议和端口号不同,它们被视为不同的源。同源(Same-Origin)是指两个URL的协议、域名和端口号完全相同。只有当这些条件都满足时,浏览器才认为这两个资源来自同一源,从而允许它们之间的交互操作。
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例