XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (2022)

Last updated at Mon, 29 Aug 2022 23:11:49 GMT

I recently wrote a blog post on injection-type vulnerabilities and how they were knocked down a few spots from 1 to 3 on the new OWASP Top 10 for 2022. The main focus of that article was to demonstrate how stack traces could be — and still are — used via injection attacks to gather information about an application to further an attacker's goal. In that post, I skimmed over one of my all-time favorite types of injections: cross-site scripting (XSS).

In this post, I’ll cover this gem of an exploit in much more depth, highlighting how it has managed to adapt to the newer environments of today’s modern web applications, specifically the API and Javascript Object Notation (JSON).

I know the term API is thrown around a lot when referencing web applications these days, but for this post, I will specifically be referencing requests made from the front end of a web application to the back end via ajax (Asynchronous JavaScript and XML) or more modern approaches like the fetch method in JavaScript.

Before we begin, I'd like to give a quick recap of what XSS is and how a legacy application might handle these types of requests that could trigger XSS, then dive into how XSS still thrives today in modern web applications via the methods mentioned so far.

What is cross-site scripting?

There are many types of XSS, but for this post, I’ll only be focusing on persistent XSS, which is sometimes referred to as stored XSS.

XSS is a type of injection attack, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to execute malicious code — generally in the form of a browser-side script like JavaScript, for example — against an unsuspecting end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application accepts an input from a user without sanitizing, validating, escaping, or encoding it.

Because the end user’s browser has no way to know not to trust the malicious script, the browser will execute the script. Because of this broken trust, attackers typically leverage these vulnerabilities to steal victims’ cookies, session tokens, or other sensitive information retained by the browser. They could also redirect to other malicious sites, install keyloggers or crypto miners, or even change the content of the website.

Now for the "stored" part. As the name implies, stored XSS generally occurs when the malicious payload has been stored on the target server, usually in a database, from input that has been submitted in a message forum, visitor log, comment field, form, or any parameter that lacks proper input sanitization.

(Video) XSS Defense - Jim Manico

What makes this type of XSS so much more damaging is that, unlike reflected XSS – which only affects specific targets via cleverly crafted links – stored XSS affects any and everyone visiting the compromised site. This is because the XSS has been stored in the application's database, allowing for a much larger attack surface.

Old-school apps

Now that we’ve established a basic understanding of stored XSS, let's go back in time a few decades to when web apps were much simpler in their communications between the front-end and back-end counterparts.

Let's say you want to change some personal information on a website, like your email address on a contacts page. When you enter in your email address and click the update button, it triggers the POST method to send the form data to the back end to update that value in a database. The database updates the value in a table, then pushes a response back to the web application's front end, or user interface (UI), for you to see. This would usually result in the entire page having to reload to display only a very minimal amount of change in content, and while it’s very inefficient, the information would nonetheless be added and updated for the end user to consume.

In the example below, clicking the update button submits a POST form request to the back-end database where the application updates and stores all the values, then provides a response back to the webpage with the updated info.

XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (1)
XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (2)

Old-school XSS

As mentioned in my previous blog post on injection, I give an example where an attacker enters in a payload of <script>alert(“This is XSS”)</script> instead of their email address and clicks the update button. Again, this triggers the POST method to take our payload and send it to the back-end database to update the email table, then pushes a response back to the front end, which gets rendered back to the UI in HTML. However, this time the email value being stored and displayed is my XSS payload, <script>alert(“This is XSS”)</script>, not an actual email address.

XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (3)

As seen above, clicking the “update” button submits the POST form data to the back end where the database stores the values, then pushes back a response to update the UI as HTML.

XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (4)

However, because our payload is not being sanitized properly, our malicious JavaScript gets executed by the browser, which causes our alert box to pop up as seen below.

XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (5)

While the payload used in the above example is harmless, the point to drive home here is that we were able to get the web application to store and execute our JavaScript all through a simple contact form. Anyone visiting my contact page will see this alert pop up because my XSS payload has been stored in the database and gets executed every time the page loads. From this point on, the possible damage that could be done is endless and only limited by the attacker’s imagination... well, and their coding skills.

New-school apps

In the first example I gave, when you updated the email address on the contact page and the request was fulfilled by the back end, the entire page would reload in order to display the newly created or updated information. You can see how inefficient this is, especially if the only thing changing on the page is a single line or a few lines of text. Here is where ajax, and/or the fetch method, comes in.

(Video) Hacking Modern Desktop apps with XSS and RCE Workshop

Ajax, or the fetch method, can be used to get data from or post data to a remote source, then update the front-end UI of that web application without having to refresh the page. Only the content from the specific request is updated, not the entire page, and that is the key difference between our first example and this one.

And a very popular format for said data being sent and received is JavaScript Object Notation, most commonly known as JSON. (Don't worry, I’ll get back to those curly braces in just a bit.)

New-school XSS

(Well, not really, but it sounds cool.)

Now, let's pretend we’ve traveled back to the future and our contact page has been rewritten to use ajax or the fetch method to send and receive data to and from the database. From the user's point of view, nothing has changed — still the same old form. But this time, when the email address is being updated, only the contact form refreshes. The entire page and all of its contents do not refresh like in the previous version, which is a major win for efficiency and user experience.

Below is an example of what a POST might look like formatted in JSON.

XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (6)

“What is JSON?” you might ask. Short for JavaScript Object Notation, it is a lightweight text format for storing and transferring data and is most commonly used when sending data to and from servers. Remember those curly braces I mentioned earlier? Well, one quick and easy way to spot JSON is the formatting and the use of curly braces.

In the example above, you can see what our new POST looks like using ajax or the fetch method in JavaScript. While the end result is no different than before, as seen in the example below, the method that was used to update the page is quite different. The key difference here is that the data we want to update is being treated as just that: data, but in the form of JSON as opposed to HTML.

XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (7)

Now, let's inject the same XSS payload into the same email field and hit update. In the example below, you can see that our POST request has been wrapped in curly braces, using JSON, and is formatted a bit differently than it was previously, before being sent to the back end to be processed.

XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (8)
XSS in JSON: Old-School Attacks for Modern Applications | Rapid7 Blog (9)

In the example above, you can see that the application is allowing my email address to be the XSS payload in its entirety. However, the JavaScript here is only being displayed and not being executed as code by the browser, so the alert “pop” message never gets triggered as in the previous example. That again is the key difference from the original way we were fulfilling the requests versus our new, more modern way — or in short, using JSON instead of HTML.

(Video) Hacking JavaScript Desktop apps with XSS and RCE - Abraham Aranguren [Security Fest 2022]

Now, you might be asking yourself, "What's wrong with allowing the XSS payload to be the email address if it's only being displayed and not being executed as JavaScript by the browser?" That is a valid question, but hear me out.

See, I've been working in this industry long enough to know that the two most common responses to a question or statement regarding cybersecurity begin with either “that depends…” or “what if…” I'm going to go with the latter here and throw a couple what-ifs at you.

Now that my XSS is stored in your database, it’s only a matter of time before this ticking time bomb goes off. Just because my XSS is being treated as JSON and not HTML now does not mean that will always be the case, and attackers are betting on this.

Here are a few scenarios.

Scenario 1

What if team B handles this data differently from team A? What if team B still uses more traditional methods of sending and receiving data to and from the back end and does leverage the use of HTML and not JSON?

In that case, the XSS would most likely eventually get executed. It might not affect the website that the XSS was originally injected into, but the stored data can be (and usually is) also used elsewhere. The XSS stored in that database is probably going to be shared and used by multiple other teams and applications at some point. The odds of all those different teams leveraging the exact same standards and best practices are slim to none, and attackers know this.

Scenario 2

What if, down the road, a developer using more modern techniques like ajax or the fetch method to send and receive data to and from the back end decides to use the .innerHTML property instead of .innerTEXT to load that JSON into the UI? All bets are off, and the stored XSS that was previously being protected by those lovely curly braces will now most likely get executed by the browser.

Scenario 3

Lastly, what if the current app had been developed to use server-side rendering, but a decision from higher up has been made that some costs need to be cut and that the company could actually save money by recoding some of their web apps to be client-side rather than server-side?

Previously, the back end was doing all the work, including sanitizing all user input, but now the shift will be for the browser to do all the heavy lifting. Good luck spotting all the XSS stored in the DB — in its previous state, it was “harmless,” but now it could get rendered to the UI as HTML, allowing the browser to execute said stored XSS. In this scenario, a decision that was made upstream will have an unexpected security impact downstream, both figuratively and literally — a situation that is all too well-known these days.

(Video) Dominik Kundel: XSS, CSRF, CSP, JWT, WTF? IDK ¯\_(ツ)_/¯ | JSConf Iceland 2018

Final thoughts

Part of my job as a security advisor is to, well, advise. And it's these types of situations that keep me up at night. I come across XSS in applications every day, and while I may not see as many fun and exciting “pops” as in years past, I see something a bit more troubling.

This type of XSS is what I like to call a “sleeper vuln” – laying dormant, waiting for the right opportunity to be woken up. If I didn't know any better, I'd say XSS has evolved and is aware of its new surroundings. Of course, XSS hasn’t evolved, but the applications in which it lives have.

At the end of the day, we’re still talking about the same XSS from its conception, the same XSS that has been on the OWASP Top 10 for decades — what we’re really concerned about is the lack of sanitization or handling of user input. But now, with the massive adoption of JavaScript frameworks like Angular, libraries like React, the use of APIs, and the heavy reliance on them to handle the data properly, we’ve become complacent in our duties to harden applications the proper way.

There seems to be a division in camps around XSS in JSON. On the one hand, some feel that since the JavaScript isn't being executed by the browser, everything is fine. Who cares if an email address (or any data for that matter) is potentially dangerous — as long as it's not being executed by the browser. And on the other hand, you have the more fundamentalist, dare I say philosophical thought that all user input should never be trusted. It should always be sanitized, regardless of whether it’s treated as data or not — and not solely because of following best coding and security practices, but also because of the “that depends” and “what if” scenarios in the world.

I'd like to point out in my previous statement above, that “as long as” is vastly different from “cannot.” “As long as” implies situational awareness and that a certain set of criteria need to be met for it to be true or false, while “cannot” is definite and fixed, regardless of the situation or criteria. “As long as the XSS is wrapped in curly braces” means it does not pose a risk in its current state but could in other states. But if input is sanitized and escaped properly, the XSS would never exist in the first place, and thus it “cannot” or could not be executed by the browser, ever.

I guess I cannot really complain too much about these differences of opinions. The fact that I'm even having these conversations with others is already a step in the right direction. But what does concern me is that it's 2022, and we’re still seeing XSS rampant in applications, but the fact that it's wrapped in JSON somehow makes it acceptable. One of the core fundamentals of my job is to find and prioritize risk, then report. And while there is always room for discussion around the severity of these types of situations, lots of factors have to be taken into consideration: A spade isn't always a spade in application security, or cybersecurity in general for that matter. But you can rest assured if I find XSS in JSON in your environment, I will be calling it out.

I hope there will be a future where I can look back and say, “Remember that one time when curly braces were all that prevented your website from getting hacked?” Until then, JSON or not, never trust user data, and sanitize all user input (and output, for that matter). A mere { } should never be the difference between your site getting hacked or not.

Additional reading:

  • Cloud-Native Application Protection (CNAPP): What's Behind the Hype?
  • Rapid7 Named a Visionary in 2022 Magic Quadrant™ for Application Security Testing Second Year in a Row
  • Let's Dance: InsightAppSec and tCell Bring New DevSecOps Improvements in Q1
  • Securing Your Applications Against Spring4Shell (CVE-2022-22965)

NEVER MISS A BLOG

Get the latest stories, expertise, and news about security today.

Subscribe

(Video) Why react applications get hacked in the real-world by Liran TAL #HIP22

FAQs

Is XSS possible with JSON? ›

XSS occurs when a user-manipulatable value is displayed on a web page without escaping it, allowing someone to inject Javascript or HTML into the page. Calls to Hash#to_json can be used to trigger XSS.

Which is the best technique to prevent XSS attacks? ›

How to prevent XSS attacks
  • Filter input on arrival. At the point where user input is received, filter as strictly as possible based on what is expected or valid input.
  • Encode data on output. ...
  • Use appropriate response headers. ...
  • Content Security Policy.

What is the main reason XSS attacks are successful? ›

XSS attacks aim to target the users of a web application, and they may be particularly effective because they appear within a trusted site.

Is XSS possible in API? ›

Cross-Site Scripting (XSS) attacks are a type of injection, in which attacker aims to execute malicious scripts in a web browser of the victim. an attacker can transfer untrusted data into the API as part of a query or command.

Is JSON parse vulnerable? ›

The built-in functions (JSON. parse()) are not vulnerable so you can use them safely. However, custom deserialization packages for JavaScript have different types of vulnerabilities, depending on the approach used to deserialize data.

What is a payload in JSON? ›

What is JSON Payload? Payload is the essential information in a data block that you send to or receive from the server when making API requests. The Payload can be sent or received in a variety of formats, including JSON.

How XSS can be prevented? ›

To protect most from XSS vulnerabilities, follow three practices: Escape user input. Escaping means to convert the key characters in the data that a web page receives to prevent the data from being interpreted in any malicious way. It doesn't allow the special characters to be rendered.

What is XSS in simple words? ›

Definition. Cross site scripting (XSS) is an attack in which an attacker injects malicious executable scripts into the code of a trusted application or website. Attackers often initiate an XSS attack by sending a malicious link to a user and enticing the user to click it.

What is the impact of XSS? ›

Cross site scripting attacks can have devastating consequences. Code injected into a vulnerable application can exfiltrate data or install malware on the user's machine. Attackers can masquerade as authorized users via session cookies, allowing them to perform any action allowed by the user account.

Which type of vulnerability allows an attacker? ›

An injection flaw is a vulnerability which allows an attacker to relay malicious code through an application to another system.

What can be stolen with XSS? ›

XSS attacks could result in session hijacking, stolen tokens, stolen session cookies and cross-site request forgery attacks. These attacks can lead to user accounts being compromised. A successful XSS attack can also enable an attacker to use stolen or forged cookies to impersonate valid users.

What is XSS in web API? ›

In a Cross-site Scripting attack (XSS), the attacker uses your vulnerable web page to deliver malicious JavaScript to your user. The user's browser executes this malicious JavaScript on the user's computer. Note that about one in three websites is vulnerable to Cross-site scripting.

Which of the following is one of the most effective ways to prevent cross site scripting XSS flaws in software applications? ›

Which of the following is most effective to prevent Cross Site Scripting flaws in software applications? Use digital certificates to authenticate a server prior to sending data.

What types of HTML tags can be used to execute XSS attacks? ›

XSS attacks may be conducted without using <script>...</script> tags. Other tags will do exactly the same thing, for example: <body onload=alert('test1')> or other attributes like: onmouseover , onerror .

Which method should be used to prevent XSS Mcq? ›

Escaping user input is one way to prevent XSS vulnerabilities in applications. Escaping means taking the data an application has received and ensuring it's secure before rendering it for the user. Doing this prevents key characters in the data that a webpage receives from being interpreted as executable code.

Which of the following is the most effective defense against reflected stored XSS? ›

To protect against reflected XSS attacks, make sure that any dynamic content coming from the HTTP request cannot be used to inject JavaScript on a page.

Does encryption protect from an XSS? ›

Websites that use SSL (https) are in no way more protected than websites that are not encrypted. The web applications work the same way as before, except the attack is taking place in an encrypted connection. XSS attacks are generally invisible to the victim.

How does WAF protect against XSS? ›

A web application firewall (WAF) is the most commonly used solution for protection from XSS and web application attacks. WAFs employ different methods to counter attack vectors. In the case of XSS, most will rely on signature based filtering to identify and block malicious requests.

Videos

1. HackTheBox - Seventeen
(IppSec)
2. XSS Defense, Past, Present and Future - Jim Manico
(secappdev.org)
3. Revisiting XSS Sanitization
(Black Hat)
4. JSON Web Tokens Suck - Randall Degges (DevNet Create 2018)
(Cisco DevNet)
5. Stranger Danger: Your JavaScript Attack Surface Just Got Bigger | SnykLIVE Recording
(Snyk)
6. Defending Web Applications Against Advanced Threats with Fortinet Machine Learning
(Tech Field Day)

Top Articles

You might also like

Latest Posts

Article information

Author: Rev. Porsche Oberbrunner

Last Updated: 08/31/2022

Views: 5738

Rating: 4.2 / 5 (73 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Rev. Porsche Oberbrunner

Birthday: 1994-06-25

Address: Suite 153 582 Lubowitz Walks, Port Alfredoborough, IN 72879-2838

Phone: +128413562823324

Job: IT Strategist

Hobby: Video gaming, Basketball, Web surfing, Book restoration, Jogging, Shooting, Fishing

Introduction: My name is Rev. Porsche Oberbrunner, I am a zany, graceful, talented, witty, determined, shiny, enchanting person who loves writing and wants to share my knowledge and understanding with you.