Improper resource allocation - TypeScript

Improper resource allocation - TypeScript

Need

Efficient resource allocation and management

Context

  • Usage of TypeScript for type-checking and compiling JavaScript code
  • Usage of Express for building web applications and handling HTTP requests

Description

Non compliant code

        import express from 'express';

const app = express();

app.get('/process', (req, res) => {
  const input = req.query.input;
  const result = expensiveComputation(input);
  res.send(result);
});

function expensiveComputation(input: string): string {
  // Simulating an expensive computation that consumes a lot of resources
  let result = '';
  for (let i = 0; i < input.length; i++) {
    result += input.charAt(i).repeat(100000);
  }
  return result;
}

app.listen(3000, () => {
  console.log('Server started on port 3000');
});
        
        

The vulnerability in this code is an example of improper resource allocation. The expensiveComputation function performs a computation that consumes a significant amount of resources. In this case, it repeats each character in the input string 100,000 times.

The issue arises when this function is called in the /process route handler. The input value is obtained from the query parameter req.query.input without any validation or restriction. This means that a user can send a request with a very long input, causing the expensiveComputation function to consume a large amount of resources.

This vulnerability can lead to resource exhaustion, where the server's resources, such as CPU and memory, are fully utilized by processing these requests. As a result, other users may be unable to access the server or experience degraded performance.

To mitigate this vulnerability, it is recommended to implement proper input validation and restriction mechanisms. This could include limiting the length of the input or implementing rate limiting to prevent excessive resource consumption. Additionally, using stable and optimized libraries for performing computationally expensive tasks can help minimize resource usage.

Steps

  • Replace the 'repeat' method with a more efficient alternative.
  • Implement input validation to prevent excessive resource allocation.
  • Consider implementing rate limiting to restrict the number of requests that can be processed within a certain time frame.
  • Monitor server resources and implement measures to prevent resource exhaustion, such as setting resource limits or implementing auto-scaling.

Compliant code

        import express from 'express';
import { RateLimiterMemory } from 'rate-limiter-flexible';

const app = express();
const rateLimiter = new RateLimiterMemory({
  points: 10, // Number of requests allowed
  duration: 1, // Time frame in seconds
});

app.get('/process', (req, res) => {
  rateLimiter.consume(1) // Consume 1 point per request
    .then(() => {
      const input = req.query.input;
      if (!validateInput(input)) {
        res.status(400).send('Invalid input');
        return;
      }
      const result = expensiveComputation(input);
      res.send(result);
    })
    .catch(() => {
      res.status(429).send('Too many requests');
    });
});

function validateInput(input: string): boolean {
  // Implement input validation logic here
  return input.length > 0;
}

function expensiveComputation(input: string): string {
  // Implement efficient computation logic here
  let result = '';
  for (let i = 0; i < input.length; i++) {
    result += input.charAt(i).repeat(1000);
  }
  return result;
}

app.listen(3000, () => {
  console.log('Server started on port 3000');
});
        
        

The fixed code addresses the vulnerability by implementing proper resource allocation practices. Here's an explanation of the changes made:

1. The code imports the necessary modules, including the 'express' module for creating the server and the 'rate-limiter-flexible' module for rate limiting.

2. An instance of the 'express' application is created using the 'express()' function and assigned to the 'app' variable.

3. A rate limiter is instantiated using the 'RateLimiterMemory' class from the 'rate-limiter-flexible' module. It is configured to allow 10 requests per second.

4. A route handler is defined for the '/process' endpoint using the 'app.get()' method. Inside the handler, the rate limiter is used to consume 1 point per request. If the rate limit is not exceeded, the handler proceeds to validate the input and perform the computation.

5. The 'validateInput' function is implemented to validate the input string. In this example, it checks if the input has a length greater than 0. You can customize this function to include more specific validation logic as per your requirements.

6. The 'expensiveComputation' function is implemented to perform the computation efficiently. It takes the input string and repeats each character 1000 times. This is just an example, and you can replace it with your own computation logic.

7. If the input is valid, the result of the computation is sent as the response. If the input is invalid, a 400 status code with an error message is sent. If the rate limit is exceeded, a 429 status code with an appropriate error message is sent.

8. The server is started on port 3000 using the 'app.listen()' method.

By implementing rate limiting and efficient computation logic, the fixed code ensures that unnecessary resources are not allocated, preventing the exhaustion of server resources and allowing other users to access the server.

References