本博客内容部分来自于
漏洞银行
公开的学习视频之中,感谢漏洞银行的无偿技术分享
。
学习跨域资源共享之前,首先要了解到的是
浏览器同源策略
这个概念。这样便于后续的跨域资源共享漏洞的理解和运用。
同源策略(Same origin policy)
是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
– 摘自:百度百科
所谓同源是指,域名,协议,端口相同。
其中:第一行和第二行均成功,是因为这两个URL相对于上面的URL来说只是不同的目录和不同的文件,但是它们相对于上面的URL来说却是`同一个域名,同样的协议,同样的端口.`
由于目前的很多项目都是前后端分离的,但是由于浏览器同源策略的缘故,因此就一定会出现跨域的问题,而处理跨域的方法有很多种类,上述只是两种处理跨域的方式。而处理跨域也就意味着可能会出现
-跨域资源共享(CORS)漏洞
.
JSONP其实已经落后了,因为通过JSONP来处理跨域的话,只能处理get请求,其他的请求方式根本无法实现。这里不做重点阐述
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源(协议 + 域名 + 端口)服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。
CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。
简单请求
。一、 请求方法是以下三种方法之一:
HEAD
GET
POST
二、HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
而浏览器对这两种请求的处理,是不一样的。
简单请求
注意,请求和响应都不包含 cookie 信息。
非简单请求
浏览器在发送真正的请求之前,会先发送一个 Preflight 请求给服务器,这种请求使用 OPTIONS 方法,发送下列头部:
上面知道了处理跨域的时候可以通过CORS来处理跨域,但是,如果你的Access-Control-Allow-Origin是可控的(本人理解为如果在response组装的时候将Access-Control-Allow-Origin的值直接从请求中获取,并不是指定某些ip和端口,那么便存在可控。),且Access-Control-Allow-Credentials为true(允许cookie跨域),那么就可以利用一个可控的网站来窃取一个人的个人隐私信息。
下面通过一副图片来看一下利用跨域资源共享(CORS)漏洞来获取站点信息的原理
该图的盗取过程基本是如下几个步骤:
1.用户登陆了一个存在跨域的网站,并且这个网站的跨域处理方式为CORS,并且开发人员处理跨域的时候满足cookie跨域和Origin是可控的。那么用户在登陆之后这个网站后,网站便会将一些cookie信息保存在浏览器中。
2. 这个时候我们向该用户发送一个钓鱼网站,用户点开这个钓鱼网站之后,钓鱼网站会向服务器发送一个Ajax异步请求,然后将返回的响应发送给攻击者。
3.1 CORS漏洞与CSRF漏洞对比
相同点:
不同点:
实战演示:
1) 使用burp来寻找一些可能存在CORS漏洞的站点。
我们将所有的请求头统一增加一个Origin参数,来满足跨域
2) 在HTTP History中做一些过滤处理
3)然后我们去访问一些网站,这样就可以看出来哪些网站是存在CORS漏洞。
3.2 "null"源问题
从上面的文章中可以知道,处理跨域到时候如果Origin可控,则会出现CORS漏洞,那么如果攻击者在发送请求的时候将Origin的值设置为
null
会发生什么?
CORS的规范中特意的提到了“NULL”源的概念,触发这个源是为了页面跳转或者是来自本地HTML文件。
目标应用可能会接收“null”源,并且这个可能被测试者(或者攻击者)利用,任何网站很容易使用沙盒iframe来获取“null 源”
上面讲解了CORS的漏洞原理和利用方式,那么该介绍怎么防护了。
实战代码:(存在CORS漏洞)
下方代码是我处理跨域问题的方式。
package com.demo.invocation;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.log.Log;
public class AjaxInterceptor implements Interceptor {
private static Log log = Log.getLog(AjaxInterceptor.class);
public void intercept(Invocation inv) {
Controller controler = inv.getController();
/** 不安全的方案**/
// 获得请求头信息
HttpServletRequest req = controler.getRequest();
// 获取请求头的 Origin 参数
String origin = req.getHeader("Origin");
// 获取请求头的 Access-Control-Allow-Headers参数
//String headers= req.getHeader("Access-Control-Allow-Headers");
// 获得响应信息
HttpServletResponse res = controler.getResponse();
//**组装响应头**//*
//客户端地址
res.addHeader("Access-Control-Allow-Origin", origin);// *号不能满需带cookie的跨域请求
// 设置响应头q
//res.addHeader("Access-Control-Allow-Headers", headers);
// 设置响应方法 允许所有方法进行跨域访问
res.addHeader("Access-Control-Allow-Methods", "*");
//设置响应预检命令的缓存时间(设置后,浏览器在该时间内只会预检一次) 单位秒
//res.addHeader("Access-Control-Max-Age", "3600");
// cookie跨域的问题 请求头解决方式
res.addHeader("Access-Control-Allow-Credentials", "true");
/** 下面为解决方案**/
/* // 获得响应信息
HttpServletResponse res = controler.getResponse();
res.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8082");// *号不能满需带cookie的跨域请求
res.addHeader("Access-Control-Allow-Methods", "GET");
//要尽可能的返回"Vary: Origin"这个头部,以避免攻击者利用浏览器缓存
res.addHeader("Vary", "Origin");*/
inv.invoke();
}
}
图中红色方框的代码就明显满足CORS漏洞的产生,当然我是用漏扫工具也扫出来了这个问题。
漏扫结果:报出了CORS漏洞
并且之前的过滤也成功实现(存在CORS漏洞)
后面,我将不安全的方案注释掉,使用安全的方案,可以看到已经不存在漏洞了。
防御方案:
1)如果响应的Access-Control-Allow-Origin值是从request中的Origin参数中获取的话,那么就会存在CORS漏洞。即下列代码
HttpServletRequest req = controler.getRequest();
// 获取请求头的 Origin 参数
String origin = req.getHeader("Origin");
HttpServletRequest req = controler.getRequest();
res.addHeader("Access-Control-Allow-Origin", origin)
2)如果响应的Access-Control-Allow-Origin值是 * 号,Access-Control-Allow-Credentials值为true的话,那么也不存在
CORS漏洞。
HttpServletResponse res = controler.getResponse();
//**组装响应头**//*
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Credentials", "true");
3) 但是从最安全的角度来讲,使用上面的建议来预防CORS漏洞是更为安全的。
下面为我的真实解决方案:
// 获得请求头信息
HttpServletRequest req = controler.getRequest();
// 判断是否为null源漏洞
String origin = req.getHeader("Origin");
if(origin.equals("null")) {
System.out.println("null 源漏洞 处理异常");
} else {
// 获得响应信息
HttpServletResponse res = controler.getResponse();
res.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8082");// 指定可信的源
res.addHeader("Access-Control-Allow-Methods", "GET");
//要尽可能的返回"Vary: Origin"这个头部,以避免攻击者利用浏览器缓存
res.addHeader("Vary", "Origin");
inv.invoke();
}
参考资料:
W3C关于CORS规范
《网络安全学习》第一部分-----初识OWASP
《网络安全学习》第二部分-----SQL注入学习
《网络安全学习》第三部分-----XSS攻击系列学习
《网络安全学习》第四部分-----SSRF服务器端请求伪造
《网络安全学习》第五部分-----远程代码执行漏洞
《网络安全学习》 第六部分-----文件上传漏洞
《网络安全学习》 第七部分-----跨域资源共享(CORS)漏洞
《网络安全学习》 第八部分-----《网络安全学习》 第八部分-----越权漏洞详解
《网络安全学习》 第九部分----CSRF(跨站请求伪造)漏洞详解
关于跨域
原理,及相关处理方案可以参考我的另一篇博客
《实战开发》AJAX跨域问题处理 ↩︎