Prevention of unauthorized server-side requests to arbitrary domains
import express from 'express';
import axios from 'axios';
const app = express();
app.get('/fetch', async (req, res) => {
const { url } = req.query;
try {
const response = await axios.get(url);
res.send(response.data);
} catch (error) {
res.status(500).send('Error fetching data');
}
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
The vulnerability in this code is a Server-side Request Forgery (SSRF) vulnerability.
In the code, there is an endpoint
/fetch
that accepts a query parameter
url
. This parameter is directly used in the
axios.get()
function to make a request to the specified URL.
The problem is that the
url
parameter is not properly validated or sanitized before making the request. This means that an attacker can manipulate the
url
parameter to make the server send requests to arbitrary domains or IP addresses, potentially leading to unauthorized access to sensitive information or performing actions on behalf of the server.
An attacker can exploit this vulnerability by providing a malicious URL that points to internal resources or sensitive endpoints that should not be accessible to the public. For example, an attacker could provide a URL that fetches sensitive data from the server's internal network, or even make requests to the server itself, leading to further exploitation.
To fix this vulnerability, the code should implement proper input validation and sanitization for the
url
parameter. The system should restrict the endpoints that can be queried and ensure that only trusted and authorized URLs are allowed. Additionally, it is recommended to use a whitelist approach, where only specific URLs or domains are allowed, rather than trying to blacklist potentially malicious URLs.
import express from 'express';
import axios from 'axios';
const app = express();
// Step 2: Implement a whitelist of allowed domains
const allowedDomains = ['example.com', 'trusteddomain.com'];
app.get('/fetch', async (req, res) => {
const { url } = req.query;
// Step 1: Validate the 'url' parameter
if (!isValidUrl(url)) {
return res.status(400).send('Invalid URL');
}
// Step 3: Check if the 'url' parameter is in the whitelist
if (!isUrlAllowed(url)) {
return res.status(403).send('Forbidden');
}
try {
const response = await axios.get(url);
res.send(response.data);
} catch (error) {
// Step 6: Return an appropriate error response
res.status(500).send('Error fetching data');
}
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
// Helper function to validate URL
function isValidUrl(url: string): boolean {
// Implement your URL validation logic here
// Return true if the URL is valid, false otherwise
return true;
}
// Helper function to check if URL is allowed
function isUrlAllowed(url: string): boolean {
// Implement your whitelist logic here
// Return true if the URL is allowed, false otherwise
return allowedDomains.some(domain => url.includes(domain));
}
The fixed code is written in TypeScript and uses the Express framework for building the server. It addresses the vulnerability by implementing several measures to prevent server-side request forgery (SSRF).
1. The code defines an array called
allowedDomains
which serves as a whitelist of trusted domains. This whitelist will be used to validate the URLs provided by users.
2. The server exposes a GET endpoint at the
/fetch
route. When a request is made to this endpoint, it retrieves the
url
parameter from the query string.
3. The code includes a helper function called
isValidUrl
which can be implemented to validate the URL provided by the user. In this example, the function returns
true
for simplicity, but you should implement your own URL validation logic to ensure the URL is valid.
4. The code includes another helper function called
isUrlAllowed
which checks if the provided URL is in the whitelist of allowed domains. The function uses the
allowedDomains
array and checks if any of the domains are included in the URL. If the URL is allowed, the function returns
true
, otherwise, it returns
false
.
5. Before making the request to the provided URL, the code validates the URL using the
isValidUrl
function. If the URL is invalid, it returns a 400 Bad Request response.
6. The code then checks if the URL is allowed by calling the
isUrlAllowed
function. If the URL is not in the whitelist, it returns a 403 Forbidden response.
7. If the URL is valid and allowed, the code uses the
axios
library to make a GET request to the provided URL. It awaits the response and sends the response data back to the client.
8. If there is an error during the request, the code catches the error and returns a 500 Internal Server Error response.
By implementing these measures, the fixed code ensures that only valid and whitelisted URLs can be requested, mitigating the risk of server-side request forgery.