Prevention of repeated requests causing service outages
import express from 'express';
const app = express();
app.get('/search', (req, res) => {
const query = req.query.q;
// Simulate a long-running process
for (let i = 0; i < 1000000000; i++) {
// Do some heavy computation
}
res.send(`Search results for: ${query}`);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
The vulnerability in the given code is a Symmetric Denial of Service (DoS) vulnerability. This vulnerability occurs because the server is performing a long-running computation in the request handler for the '/search' route.
In the code, when a GET request is made to the '/search' route, the server receives a query parameter 'q' from the request. However, instead of immediately processing the query and sending the search results, the code simulates a long-running process by executing a for loop that performs heavy computation.
This can lead to a denial of service situation because the server is unable to handle other requests while it is busy with the long-running computation. If multiple clients make simultaneous requests to the '/search' route, the server's resources can be exhausted, causing the server to become unresponsive or slow down significantly.
An attacker can exploit this vulnerability by repeatedly sending requests to the '/search' route, effectively overwhelming the server and denying access to legitimate users.
To mitigate this vulnerability, it is recommended to set a timeout for the long-running computation. This way, if the computation takes too long, the server can cancel it and respond with an appropriate error message or terminate the request.
import express from 'express';
const app = express();
app.get('/search', (req, res) => {
const query = req.query.q;
// Set a timeout of 5 seconds
const timeout = setTimeout(() => {
res.status(503).send('Request timed out');
}, 5000);
// Simulate a long-running process
for (let i = 0; i < 1000000000; i++) {
// Do some heavy computation
}
clearTimeout(timeout);
res.send(`Search results for: ${query}`);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
The fixed code addresses the vulnerability by implementing a timeout mechanism for long-running requests.
In the code, we import the Express framework and create an instance of the application. We define a route for the '/search' endpoint using the HTTP GET method.
Within the route handler, we first extract the query parameter from the request object.
To prevent the server from becoming unresponsive due to a long-running process, we set a timeout of 5 seconds using the
setTimeout
function. If the request takes longer than 5 seconds to process, the timeout callback function will be executed.
Next, we simulate a long-running process by using a for loop that performs heavy computation. This is where the actual processing of the request takes place.
Before sending the response, we clear the timeout using the
clearTimeout
function. This ensures that if the request completes within the timeout period, the timeout callback function will not be executed.
Finally, we send the response with the search results.
By setting a timeout and clearing it before sending the response, we ensure that requests that take too long to process will be terminated and the server will not be overwhelmed.