Understanding the WHY behind technological concepts is extremely important to understanding the concept at a fundamental level.
Numerous concepts in the Web Security field often get ignored because of their apparent complexities.
One such concept is “Pre-flight Requests”.
Straightforward concept, but often ignored.
Let me ask you: Do you know what pre-flight requests are?
If you answered “Yes”, kudos to you.
If you answered “No”, let me ask you a follow-up question.
Have you seen those seemingly useless OPTIONS requests in your Burp Proxy History when testing web applications?
These pesky OPTIONS requests are the answer to the earlier question. These are pre-flight requests.
But, why do you see them so often in your proxy history? What purpose do they serve?
Before diving into understanding pre-flight requests, you should understand the concept of CORS well. If you do not understand, here’s a link to my previous post that will help you understand the fundamentals of CORS.
Now, let’s dive into pre-flight requests.
During Javascript execution, when your browser sees a cross-origin request, it does not just send the request immediately.
A cross-origin request by definition violates the Same Origin Policy.
However, since the introduction of CORS, browsers have been updated to validate the destination server’s CORS policy before sending or dropping the request.
So, how exactly does the browser check the destination server’s CORS policy?
That’s where the pre-flight request comes into play. If you ponder over the name “pre-flight”, you can get a sense of what it means.
This name comes from the aviation terminology “pre-flight check”, which is a series of inspections that a pilot performs before each flight to ensure the aircraft is safe to operate.
Similarly, the browser performs an inspection of the request before sending it, to ensure that SOP is not violated.
So, what does this pre-flight OPTIONS request contain?
- The pre-flight request is sent to the same endpoint where the subsequent request is going to be sent
- Additionally, the request contains what METHOD is going to be requested,
- what non-standard headers are going to be sent in the request, and
- what’s the current Origin
The remote server can form a pre-flight response customized to every pre-flight request or it can serve a standard response for all pre-flight requests.
In response to the pre-flight requests, the remote server tells the browser:
- What origins it is willing to accept requests from (Access-Control-Allow-Origin),
- what methods it is willing to accept in cross-origin requests (Access-Control-Allow-Methods),
- what headers are OK to be sent in cross-origin requests (Access-Controls-Allow-Headers), and
- most importantly, whether the browser should automatically attach cookies to cross-origin requests (Access-Control-Allow-Credentials).
If the subsequent cross-origin request matches the conditions mentioned in the pre-flight response, the browser gets a green signal to send out the request.
If any of the condition violates the cross-origin request supposed to be sent, the browser will throw an error and drop the subsequent request.
That’s pre-flight requests in a nutshell.
But, hold on, that’s not all. Pre-flight requests are not always sent. There are some exceptions to the above rule.
But, that’s a topic for another day. If you are curious, go ahead and google “Simple requests v/s pre-flighted requests”.