Open Mobile Menu

Blog

Filed In: Application Security, Security

Using the Same-origin Policy to Control for Cross-Site Request Forgery

Views: 294

Written By: Scott Simmons July 23, 2018

Cross-Site Request Forgery (CSRF) is a security issue which can allow legitimate users to be tricked into performing actions in your web application on behalf of a malicious attacker. A successful phishing attack or similar scheme could be leveraged to exploit a CSRF vulnerability. It’s a serious issue which can be difficult to detect without manual penetration testing. The solution to this problem is often to issue a per-session token to each logged-in user, place that token in a hidden field in the page (or in some cases within a request header), and then confirm that any request performing a significant transaction contains the correct token. For example, the following raw HTTP request to add a new user to the example.com application contains a token called “antiCSRF_token”. If the application is checking to make sure that this parameter is the correct one for the logged-in user, this transaction is protected from CSRF attacks.

This looks great. If an attacker wants to create a CSRF attack targeting this “addUser” transaction they will need to somehow guess the user’s “antiCSRF_token” value for that session or transaction.

Now let’s take a look at the same transaction being performed in a different way.

At first glance, we might worry that this request is vulnerable to CSRF. With no anti-CSRF token, how can the server be sure that the request is genuine? Can’t an attacker generate some code which will create a new user if they can trick an administrator into loading it?

CSRF vs XHR

The answer is that this request is performed by the client-side application in the user’s browser executing an XMLHttpRequest (XHR) method and specifying the “application/json” Content-Type. XHR is a JavaScript object which can send HTTP requests to a target server, much like a more traditional form-based request. The key difference is that modern browsers know better than to let this kind of JavaScript communicate with any domain except for the one where it came from. This is the Same-origin Policy. So in the case of the second request above, the client’s browser sees an XHR with content type “application/json” sending some data to create a new user. It sees that the XHR code was loaded from example.com and that the request is being sent to example.com, so it sends it. If JavaScript code from attacker.com were to try and send this request to example.com, the user’s browser would see that the origins were not the same, and would not execute the request.

The transaction is protected from CSRF attacks by virtue of the fact that any code which is going to perform a request of this type must be from the same origin. If every transaction in your application is performed this way and you’ve made sure that the server only accepts requests with the “Content-Type: application/json” header, you’ve prevented CSRF without an anti-CSRF token.

It’s worth highlighting two important components of this. First, it’s critical to ensure that the server only accepts the correct Content-Type. In the example above we want to make sure that it rejects anything that isn’t “application/json”. Be sure to verify this through testing; many servers can be very forgiving when it comes to accepting incorrect Content Types which can completely undermine this approach to stopping CSRF attacks. Second, double check to make sure that the type of request in use is one of the types which obey the Same-origin Policy. Some XHR requests don’t care if they’re carrying data from one domain to another; these are called “simple requests”.

Exception 1: Unique Functionality

When performing penetration tests, we often see web applications which are built using one of the many common frameworks which perform transactions using XHRs. Using a well-supported and up-to-date off-the-shelf framework can be a great idea when it comes to web application security. It’s likely that the developers of the framework have already integrated fixes for any number of security issues that you may never even heard of! The catch is that every web application is unique and often a framework won’t have every single thing you need for your application. When this happens, sometimes the solution is to find some pre-written code and roll that into your app. Sometimes the solution is just to create that extra bit of functionality yourself.

These are the places where security specialists (and malicious attackers) will look closely for security vulnerabilities, including CSRF. In the above example where we’re relying on the Same-origin Policy to prevent CSRF, the /admin/addUser transaction is protected. However, what if the application also allows administrators to upload a file with a list of users to be added? Here’s a sample request performing this bulk user addition.

This is a “multipart/form-data” request rather than an “application/json” request, and unfortunately the Same-origin Policy does not apply. The server can check to ensure that the Content-Type is “multipart/form-data,” but this won’t help defend against CSRF because these types of requests can be sent cross-domain (even if it’s sent by an XHR). We can create a form which will send a request to this /admin/bulkAddUser transaction, and if an administrator loads this content, no matter where it is hosted, the request will be sent and the attacker’s users will be created.

When decoded, the data in this code contains two users: Attacker (attacker@evilsite.com) and BadGuy (badguy@anotherevilsite.com). 

So remember to examine each transaction to ensure that appropriate controls are in place, and pay special attention to the more customized areas of your application.

Exception 2: CORS Policy

Because we are relying on the Same-origin Policy to prevent CSRF attacks, it’s important that we understand the Cross-Origin Resource Sharing (CORS) policy. Sometimes, a website will want to allow JavaScript from other sites to interact with its content. Maybe a site distributes non-sensitive product info to partner sites, or maybe it wants to deliver uptime data for a video game server, or maybe it has an API which sends the latest weather report for a given zip code. This data isn’t sensitive from an application security perspective and so maybe they want to allow other sites to request information regardless of the originating domain. This kind of data sharing can be accomplished with a properly configured Cross-Origin Resource Sharing policy. This policy is passed to the browser in response headers, something like the following example.

These headers tell the browser that it’s okay to ignore the Same-origin Policy for example.com as long as the requesting JavaScript comes from https://friendlywebsite.com.

This is important as we think about stopping CSRF with the Same-origin Policy because we need to be sure that we trust the security at friendlywebsite.com. Let’s say an attacker is able to place malicious code on that domain, which could be accomplished by executing a complex takeover of that app or by exploiting something as simple as a content spoofing flaw on an arbitrary forum page. If that happens we’ve indirectly exposed example.com to attack because it’s been configured to trust content from friendlywebsite.com.

Now You’re Ready to Get Pentested

If you’re going to rely on the Same-origin Policy to control for Cross-Site Request Forgery attacks, remember the following. Ensure that every transaction in the application is of a type which is required to obey the Same-origin Policy. If you’re using Cross-Origin Resource Sharing, make sure that it grants access to trusted domains and no others. If you’ve done these things properly, you shouldn’t have to worry about seeing CSRF show up on your next pentest report.

Scott Simmons

Scott Simmons is a Security Consultant at AppSec Consulting who specializes in the area of application security. He has extensive expertise in application penetration testing, including the use of manual techniques and automated tools to perform detailed assessments of a wide variety of applications, including web applications, web services, and mobile applications. He also has led numerous projects that involve training customers and team members on how to master application security testing tools and techniques. Scott provides targeted, practical advice to customers on how best to mitigate security vulnerabilities and keep their sensitive information well-protected.

Scott earned his undergraduate degree from the University of California at Berkeley and holds a certificate in Software Development from the Community College of Allegheny County. Before working in security, he developed fault-tolerant software for an international transportation infrastructure company. He has conducted web security training classes for multinational clients in the San Francisco Bay Area, in India, and in China.

read more articles by Scott Simmons