CORS Request & CSRF Attack

Posted on 2021-06-11  2 Views


In the recent development of the front-end and back-end separation projects, the problem of CORS requests was frequently encountered. While the train of thought is still clear, make a memo note here.

Some of the contents of this article are referenced from the following sources, and we would like to express our deep thanks: MDN Official Document - Cross-origin Resource Sharing
(CORS) Cross-origin Resource Sharing CORS
Detailed Explanation - Ruan Yifeng's Web Logs

What is CORS?

According to the definition given by MDN:

Cross-origin resource sharing (CORS) (or colloquially translated as cross-origin resource sharing) is an HTTP header-based mechanism that allows the browser to access and load these resources by allowing the server to mark other origins (domains, protocols, and ports) other than its own. Cross-origin resource sharing also checks whether the server will allow genuine requests to be sent through a mechanism that initiates a "preflight" request to a server-hosted cross-origin resource through the browser. In the preflight, the headers sent by the browser are marked with HTTP methods and headers that will be used in real requests.

For example, if the front-end page runs on a http://localhost:8080, when a user accesses a front-end resource, such as http://localhost:8080/index.html, http://localhost:8080/1.html, etc., the request for those resources will not involve cross-domain issues. When the browser needs to access the backend resources running on the http://localhost:8081, the browser will perform cross-origin requests because the port numbers are not the same.

Schematic diagram of a CORS request given by MDN

A key concept is involved in the previous definition: Origin, which is what we often call a domain, or source. We can categorize all HTTP requests as same-origin requests and cross-origin requests. We use the following to determine whether a request is cross-domain:

  • Protocol type (HTTP/HTTPS)
  • domain name
  • Port number

Only when the current page and the above three items of the requested resource are consistent, it is a same-origin request, otherwise it will be treated as a cross-origin request. It should be noted here that DNS translation will not occur when the domain name matches, which means that the http://localhost:8080 and http://127.0.0.1:8080 are also not in the same domain.

CORS requests

According to the specific content of the sent request, we can divide HTTP requests into simple requests and non-simple requests. When processing simple requests, the browser does not need to send a preflight request, while when processing a complex request, the browser first sends an OPTION preflight request to the server to obtain whether the server allows access to the resource in CORS mode. We'll cover more about preflight later.

Simple request

When the HTTP request method is one of the following:

  • GET
  • HEAD
  • POST

And the HTTP request header only includes the following fields:

When the Content-Type field is one of the three (application/x-www-form-urlencoded, multipart/form-data, text/plain), the request can be regarded as a simple request.

Request and respond to messages

# Request Packet
GET /resources/public-data/ HTTP/1.1 
Host: bar.other 
Accept-Language: en-us,en; q=0.5
Connection: keep-alive 
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html 
Origin: http://foo.example 
# Response Packet
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: application/xml

The Origin in the request packet and the Access-Control-Allow-Origin of the corresponding packet together form the most basic header field. The Origin field indicates the source of the request, and the Access-Control-Allow-Origin returned by the server specifies the cross-domain access source accepted by the server. * indicates acceptance of all external cross-domain access.

Preflight requests

The preflight request needs to send an OPTIONS request to the server before the actual request is sent to find out whether the server supports CORS, which Origins it supports, what requests it supports, and what headers it supports.

Request and response headers

 # Request header
 
# Actual request method
 Access-Control-Request-Method: POST 
 # Headers included in the actual request
 Access-Control-Request-Headers: X-PINGOTHER, Content-Type 
 # Response header
 
Access-Control-Allow-Origin: http://foo.example
 Access-Control-Allow-Methods: POST, GET, OPTIONS
 Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
 # Request validity period: During the validity period, the browser does not need to send OPTIONS preflight requests repeatedly
 Access-Control-Max-Age: 86400 

XSS & CSRF attacks

XSS attacks

XSS (Cross-site-Script Cross-Site Scripting Attack), usually caused by data with page parseable content being inserted directly into the page without processing. XSS is divided into stored XSS, reflected XSS, and MXSS (also known as DOM XSS) according to the location of the attack script.

Stored XSS

It is more common in blogs, forums, and other pages that allow users to enter content. XSS injection scripts are persisted to the database. To take the simplest example, without any processing of user input by the back-end program, user input:

<script>alert("This is low level")</script>

When the browser accepts the data sent back by the backend and parses it into <script> tag, this code is loaded to implement the attack.

Reflective XSS

It is more common when an attacker directly provides a URL to the user, directs the user to click and attack. For example:

https://malicious.link/q="%2F><script>alert%28document.cookie%29</script>

If the HTML in the web page uses the query parameter, the above attack code will be parsed, thereby exposing the user's cookies.

Common defenses include replacing special characters such as <> with HTMl escape symbols, or matching the parenthesis content and replacing them with regular expressions.

CSRF attack: impersonating the user's hand

The full name of CSRF is Cross Site Request Forgey. It can be understood simply that an attacker has stolen the user's identity and sent malicious requests in the user's name.

What is Cross-site Request Forgery (CSRF)? - Creative Ground Technologies
Illustration of CSRF attack

As shown in the figure above, a typical CSRF attack is divided into four steps:

  • The user logs in to a trusted website A
  • Official website A generates a cookie and stores it in the user's browser
  • Without logging out A, visit the phishing website B provided by the hacker
  • Phishing websites use the user's browser to make requests and bypass the same-origin detection mechanism by <img src="xxx">

CSRF defense

(1) Verify the HTTP Origin & Referer field

When a phishing website sends a request to a trusted website, the hacker will put its domain name in the Origin (except IE11-, 302 redirect) and Referer fields, and cannot be modified by the front-end code. When performing critical operations, the backend server needs to verify that the HTTP request header is from a trusted address.

(2) Add CSRF tokens

Based on the above attack process, we conclude that hackers can only use the user's browser to send cookies, and cannot directly obtain the cookie. Therefore, we can generate CSRF tokens on the backend and store them in the backend session. Enter the token into the page and add a hidden CSRF token field to the front-end page form, the value of which is usually hashed encrypted with the username, time, etc. When the server receives the request, it needs to verify that the encrypted string of the token is correct and that the timestamp is not expired.