JAVASCRIPT
Prevent Server-Side Request Forgery (SSRF) Attacks
Protect your server from SSRF vulnerabilities by validating URLs and restricting outbound requests to untrusted or internal networks in Node.js applications.
// Install: npm install url is-localhost-ip axios
const { URL } = require('url');
const isLocalhostIp = require('is-localhost-ip'); // To check loopback and private IPs
const axios = require('axios');
function isValidOutgoingUrl(inputUrl) {
try {
const url = new URL(inputUrl);
// Block non-HTTP/HTTPS schemes
if (!['http:', 'https:'].includes(url.protocol)) {
return false;
}
// Block requests to localhost or private IPs (SSRF prevention)
// This is a crucial step to prevent access to internal services.
if (isLocalhostIp(url.hostname)) {
console.warn(`SSRF attempt blocked: Localhost IP detected for ${url.hostname}`);
return false;
}
// Optional: Block specific internal IP ranges if `is-localhost-ip` isn't enough for your network
// Example: Block 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
// You'd need a more robust IP range checker for this.
// Further validation: Ensure the hostname is not a literal IP if not intended
// or check against a whitelist of allowed domains.
// For simplicity, we assume any public domain is acceptable after prior checks.
return true;
} catch (e) {
console.error("URL parsing error:", e.message);
return false;
}
}
async function makeSafeHttpRequest(targetUrl) {
if (!isValidOutgoingUrl(targetUrl)) {
console.error(`Blocked unsafe URL: ${targetUrl}`);
throw new Error('Unsafe URL detected. Request blocked.');
}
try {
const response = await axios.get(targetUrl, { timeout: 5000 }); // Add timeout for safety
return response.data;
} catch (error) {
console.error(`Error making HTTP request to ${targetUrl}:`, error.message);
throw new Error('Failed to fetch data from external URL.');
}
}
// Example usage:
/*
async function runSSRFTest() {
// Safe URL
try {
const publicData = await makeSafeHttpRequest('https://jsonplaceholder.typicode.com/todos/1');
console.log('Public data fetched:', publicData);
} catch (e) {
console.error(e.message);
}
// Unsafe URL (example of a blocked internal IP)
try {
const internalData = await makeSafeHttpRequest('http://127.0.0.1:8000/internal-api'); // Loopback IP
console.log('Internal data fetched:', internalData);
} catch (e) {
console.error(e.message);
}
try {
const privateIpData = await makeSafeHttpRequest('http://192.168.1.1/admin'); // Private IP
console.log('Private IP data fetched:', privateIpData);
} catch (e) {
console.error(e.message);
}
}
runSSRFTest();
*/
How it works: Server-Side Request Forgery (SSRF) allows attackers to trick a server into making requests to internal or other sensitive systems. This snippet provides a robust `isValidOutgoingUrl` function that validates a URL before the server initiates an outgoing request. It blocks non-HTTP/HTTPS schemes and, critically, uses `is-localhost-ip` to prevent requests to loopback addresses (`127.0.0.1`, `::1`) and known private IP ranges (e.g., `10.x.x.x`, `192.168.x.x`). This prevents an attacker from using your server as a proxy to scan internal networks or access sensitive resources. A timeout is also added to the request to prevent long-running or hanging connections.