React Excessive
Data Exposure:
Examples and Prevention

stackhawk

StackHawk|May 3, 2022

Learn and understand what excessive data exposure is and how you can prevent it in your React application.

Do you ever wonder what happens with all the extra data your server sends that the front end doesn't consume? Or what to do with all the extra information in the JSON object you get from your back-end APIs? 

This scenario often leads to a potential vulnerability called excessive data exposure. The end result is that attackers can use the extra sensitive data that's exposed to do something harmful to your users. But what exactly is excessive data exposure? How can it be harmful? And how can you prevent it in your front-end React application? 

In this post, I'll answer these questions for you. I'll help you understand excessive data exposure with examples and how you can prevent it in your React application.

What Is Excessive Data Exposure?

Excessive data exposure is a security vulnerability that occurs when your front end requests more data than desired. In web applications, anyone can open the browser developer tools and inspect incoming and outgoing HTTP requests. They can see the data payload received from these requests. 

Thus, even if the front end doesn't necessarily use or consume this data, an attacker can still look at that data via the API call. In cases where an API sends more data that may be sensitive in nature than the front end requires, an attacker can use this data to cause damage to the users. 

This is known as excessive data exposure.

In excessive data exposure, there is literally more sensitive data being exposed than anyone has access to.

Now let's understand this further with the help of an example.

Example of Excessive Data Exposure

Imagine you have an e-commerce store. You also have a large number of users and potential shoppers who regularly check out items from your store. Let's say that in order to finalize a purchase, your users have to check their credit card details as well as their order details. On the "Confirm Orders" page, you allow users to review what they want to purchase. 

Then, on the "Checkout" page, you prompt them to check their credit card details. However, there is a single REST API endpoint for this page. This endpoint brings the items in your cart as well as your credit card details. Here's what the user flow might look like: 

React Excessive Data Exposure: Examples and Prevention
 image

Now imagine if you as a user could share your cart items with a friend. That would generate a shareable URL for your "Confirm Orders" page where an authenticated user can only view data but not modify it. Sounds cool. But as soon as this page loads, you're hitting an API endpoint that also retrieves that user's credit card details. An attacker might steal this information to cause potential damage to this user. 

How to Prevent Excessive Data Exposure

The most straightforward approach to preventing excessive data exposure is to refactor your REST API endpoints. If you know that your web service is sending out sensitive data that the front end doesn't need, you need to filter that data in your back-end query itself. This will essentially serve two purposes: preventing unwanted sensitive data from being exposed by the API and optimizing your database query. 

However, the first solution is purely server-side. What if you're using a third-party web service over which you don't have much control? How will you prevent excessive data exposure from a front-end-based approach? 

Instead of using REST APIs, you can use GraphQL-based APIs. GraphQL is an API architecture that gives the front end full control over what data it wants. Thus, now you can use this approach to request only non-sensitive data on the front. Let's see how we can use GraphQL to prevent over-fetching in a React application. 

Set Up a React App

As a first step, we'll go ahead and create a new React application by running the following: 

npx create-react-app react-excessive-data-exposure-app

That should create a brand new and fresh React project for us. Next, go ahead and edit the contents of the App.js file as shown below: 

import './App.css';


function App() {
return (
<divclassName="App">
<headerclassName="App-header">
<h1>React Excessive Data Exposure with GraphQL</h1>
</header>
</div>
);
}


export default App;

Now let's run the React app locally. To do so, you'll need to run the following command inside the root directory: 

npm start

Then if you visit "http://localhost:3000", you should see the following page:

React Excessive Data Exposure: Examples and Prevention image

Using Public GraphQL API

To demonstrate how we can use GraphQL to overcome excessive data exposure, we need a GraphQL server or API first. To keep things simple, we won't go out and create our own GraphQL API or server from scratch. Rather, we'll use a dummy mock GraphQL API online to get things rolling quickly. We can then communicate with this GraphQL API from the React app we created in the previous section to understand how we can prevent the over-fetching of data on the front end. 


For this purpose, we'll use GraphQLZero, a free fake online GraphQL API. Let's understand the use case and example on this API. We can visually test out the API, request, and response structure via the GraphQL playground using this tool. On the left-hand side, you'll find an editable section. This is where we can write our GraphQL queries.

React Excessive Data Exposure: Examples and Prevention
 image

Add the following query to this section:

query {
  user(id: 1) {
    id
    username
    email
    address {
      geo {
        lat
        lng
      }
    }
  }
}

Then click on the big Play button in the middle. That should display a JSON response in the right section: 

React Excessive Data Exposure: Examples and Prevention
 image

Great! Now we'll communicate to this GraphQL API via our React app. So let's do that. 

Excessive Data Exposure in React

Inside App.js, we'll first import the useState hook from React so we can store the data obtained from an API call. We'll also import the useEffect hook so we can use the componentDidMount life cycle equivalent's in hooks to make an API call as soon as the page loads. 

import {useEffect, useState} from 'react';

Next, we'll make use of the useState hook to create a state variable to store the API's data: 

const [userData,setUserData]=useState();

After that, we'll create a local variable inside our App component to hold our GraphQL API's query. It's a simple string that holds the exact query we tested previously, as shown: 

const QUERY=`{
    user(id: 1) {
      id
      username
      email
      address {
        geo {
          lat
          lng
        }
      }
    }
  }`

After that, we'll create a useEffect, and inside the callback function, write the code to create a GraphQL API request to our mock server using JavaScript's Fetch API. Here's what that looks like:

 useEffect(()=>{
    fetch("https://graphqlzero.almansi.me/api", {
      "method": "POST",
      "headers": { "content-type": "application/json" },
      "body": JSON.stringify({
        query: QUERY
      })
    }).then(res => res.json())
    .then(data=>setUserData(data.data.user))
  },[])

Since we have to pass the QUERY object, each GraphQL API is a POST request, which is why the method is POST in the above code. Then, in the body part of the request, we send the query for the API call in JSON string. Finally, we tackle two .then callbacks to convert the response to JSON and consequently store it inside our state variable. 


Next, we'll display this data in our App.js file:

    <div className="App">
      <header className="App-header">
        <h1>React Excessive Data Exposure with GraphQL</h1>
        <div className='data'>
          <div>Username:  <span>{userData?.username}</span> </div>
          <br/>
          <div>User ID:  <span>{userData?.id}</span> </div>
          <br/>
          <div>Email:  <span>{userData?.email}</span> </div>
         
        </div>
      </header>
    </div>


Note that we're only interested in the username, ID, and email. So we extract those data from the API and then render them on the DOM. Once you do that, here's what your React app should look like:

React Excessive Data Exposure: Examples and Prevention
 image

That's cool. But let's inspect the API call inside the browser's network tab. 

React Excessive Data Exposure: Examples and Prevention image

If you notice, we're only using some information like email, username, and ID, but we also get the user's address back in the response. Clearly, we're overreaching data on the front end.

If this data is exposed to an attacker, it can lead to excessive data exposure. So how can we prevent it?

Prevent Excessive Data Exposure in React

If we were working with a REST API, it would have been impossible to get around this via a pure front-end solution. Especially in this case, since we're using a third-party API, we have no control over how the API is structured, what data it sends, etc. Luckily, we're working with a GraphQL API where the front end can control what data it wants from the request. 

Hence, all we need to do is update our query. Here's what the updated query looks like: 

  const QUERY=`{
    user(id: 1) {
      id
      username
      email
    }
  }`

Now let's see what data we get back from the API: 

React Excessive Data Exposure: Examples and Prevention image


Now we only get the user ID, username, and email back. Awesome! We have prevented unwanted and potentially sensitive information from being exposed on the front end. 

Find and Fix Security Vulnerabilities

Conclusion

I hope I was able to help you understand what excessive data exposure is and how you can prevent it in your React application. If you're working with a REST-based back-end architecture, a correct way to tackle this would be to refactor the backend API so that it returns only the required data. Until next time! 

This post was written by Siddhant Varma. Siddhant is a full-stack JavaScript developer with expertise in frontend engineering. He’s worked with scaling multiple startups in India and has experience building products in the Ed-Tech and healthcare industries. Siddhant has a passion for teaching and a knack for writing. He's also taught programming to many graduates, helping them become better future developers.


StackHawk  |  May 3, 2022