CSRF, which stands for Cross-Site Request Forgery, is a common attack vector for vulnerable web applications with potentially catastrophic consequences. At number 8 in the 2013 OWASP TOP 10*, CSRF is an age-old attack that has been well-known by both hackers and implementers .
While there is a multitude of accepted prevention techniques, each has its pros and cons. Amongst the most popular and recommended techniques are ones that implement a CSRF Token. The CSRF Token technique requires that all state-changing endpoints accept an additional parameter (i.e. the CSRF Token) whose value was sent alongside the html/css/js of the web application. Upon each request, the web application’s backend server verifies the correctness of this token and rejects the request if it does not correspond to the session. A decent analogy is that while session cookies authenticate the request’s browser, CSRF Tokens authenticate the code that’s making the request. While effective, a downside to the CSRF Token pattern is that it requires stringent developer effort and changes to client-side code.
Beyond CSRF Tokens, there are many other techniques that aim to thwart CSRF attacks . Each technique depends on certain assumptions of the web application security model, especially the Same Origin Policy (SOP) which is implemented by all modern browsers today.
In this post, I provide a quick summary of CSRF and the SOP, while highlighting a few shortcomings of the SOP in thwarting CSRF attacks. Then, I discuss a suite of prevention techniques that don’t involve CSRF Tokens and bring attention to their pros and cons.
*In the updated 2017 OWASP Top 10, CSRF has been “retired, but not forgotten.”
CSRF is the execution of a “forged” request to a web application's backend server from an unknown origin. The scenario can best be explained by example:
In the example, it’s important to note that the victim had to be tricked into visiting the malicious website. This trickery is the result of Social Engineering. Such carefully executed Social Engineering is not always needed to perform CSRF attacks, however. In fact, every single webpage you visit can perform CSRF; surfing the Web requires a lot of trust.
Fortunately for users like you, security-minded implementers have introduced CSRF preventions into their web applications that would prevent catastrophic scenarios like the one in the banking.example.com example. As mentioned previously, CSRF Tokens are one such prevention technique. Many of these techniques depend on the Same Origin Policy.
The Same Origin Policy (SOP) is a critical component of the web application security model. It outlines a series of policies and rules for how code and data can interact across origins and is implemented by all modern web browsers.
One of the major goals of the SOP is to prevent malicious websites from accessing sensitive information or making state-changing requests to other web applications. While the SOP has been widely successful at thwarting a Pandora’s Box of problems, there are subtleties that can still leave web applications vulnerable to cross-origin attacks like CSRF, as discussed below.
Despite the various rules and restrictions outlined by the SOP, there are certain resource-sharing actions that are unrestricted.
One type of relaxed restriction is the ability to embed cross-origin content via the following HTML tags :
It’s also important to note that when embedding these resources, you’re instructing the browser to make HTTP(S) GET requests.
While the following look’s strange, your browser would execute the GET request without restriction.
It’s irrelevant whether the response is a valid image — the request is still executed. This is why it’s important that state-changing endpoints on your web application cannot be invoked with the GET method.
Unfortunately, it’s not that simple.
There are also ways to execute POST requests without restriction by the SOP. These request formulations are where the most damage is done by CSRF.
But why in the world does the modern web infrastructure allow such madness?
A likely explanation is that to deprecate this functionality would mean lots of breaking changes to the millions of web applications deployed globally. This functionality is a legacy feature that will likely not be changed in the name of backwards compatibility.
It turns out that there are limits to the formulation of the request itself. To highlight a few:
Unfortunately, it’s yet-again not that simple.
Certain unrestricted cross-origin requests can also be formulated using XHR/fetch. All requests can in fact be classified into 1 of 2 bins: “simple” and not “simple” . Cross-origin “simple” requests can be freely sent under the SOP.
A “simple” request is one that meets the following conditions:
It’s interesting to note that the cross-origin requests allowed by various HTML tags are a strict subset of these “simple” requests.
Yes, with one distinction:
At last, this is where the SOP comes to the rescue!
In this scenario, before making the request, the browser will send a “preflight” request to the target resource URI. A preflight request uses the OPTIONS method and allows the server to respond with a whitelist of allowed actions. This whitelist is used by the browser to determine if the request is allowed. If the request oversteps its bounds, the browser will block the request. It won’t be sent. Plain and simple.
The whitelist of allowed actions is called a Cross-Origin Resource Sharing (CORS) policy. CORS lets web application developers deliberately and intentionally relax certain constraints of the SOP. This is important because making “non-simple” cross-origin requests are still an important functionality of many web applications.
This question hints at a suite of CSRF prevention techniques that don’t depend on CSRF tokens. The techniques can be summarized as follows:
An example technique that falls into this suite would be a web application server whose endpoints require the presence of a Content-Type header with the value, application/json.
Yes, in theory.
But in practice, this is not always the case. Ugh, more caveats!
To assume protection from CSRF by requiring only “non-simple” requests is to trust the browsers’ implementation of very nuanced details of the Same Origin Policy. As others have pointed out, historically there have been various bugs and loopholes that have allowed hackers to bypass preflight for “non-simple” requests . Prominent examples include a vulnerability in Flash that allowed for non-standard headers to bypass preflight, and a bug in Chrome’s Navigator.sendBeacon API which allowed for non-standard values in the Content-Type header to bypass preflight [6,7].
There are arguments for why certain CSRF-prevention techniques that force requests to be “non-simple” are not sufficient enough to prevent CSRF (e.g. the bugs and loopholes referenced above). But even the arguments in favor of CSRF Tokens, however, depend on the proper implementation of the SOP (i.e. not allowing read-access to the response of a cross-origin request). So from the many points of view, we are all placing trust in our friends who are implementing modern browsers to adhere to the SOP. Web security in general requires faith and trust in a lot of different people, institutions, hardware, and software.
If there are only a few things I hope you take away from this post, they’re these:
At Posh, we are bringing modern Conversational AI to the forefront. Our mission is to make natural conversation the new user interface.