Learn how to prevent Server Side Request Forgery (SSRF) attacks with real code examples and best practices. Protect your application from SSRF vulnerabilities and security threats.
Server Side Request Forgery (SSRF) is a web security vulnerability that allows attackers to induce the server-side application to make requests to unintended locations. It occurs when an application accepts user-supplied URLs without proper validation, allowing attackers to manipulate the server into making malicious requests.
The attacker can potentially:
Access internal services behind firewalls
Scan internal networks
Interact with cloud service metadata endpoints
Execute remote code in some cases
Perform denial of service attacks
This guide covers SSRF attacks, examples, prevention methods, and how to test for SSRF vulnerabilities using real-world techniques.
One Simple SSRF Attack Example
Consider this classic example of a URL fetch:
String url = request.getParameter("url");
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
An attacker could provide this input for the URL:
http://internal-service:8080/admin
The resulting request would attempt to access:
http://internal-service:8080/admin
This allows the attacker to access internal services that should not be publicly accessible.
SSRF Prevention Methods: How to Fix Your Code
The most efficient way to fix an SSRF issue in your code is implementing proper URL validation, including whitelisting allowed domains and blocking requests to internal networks.
URL validation should include checking the protocol, domain, and path against an allowlist of permitted values, and ensuring requests cannot be made to private IP ranges or internal hostnames.
Code Samples
Vulnerable Code
String url = request.getParameter("url");
URL obj = new URL();
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
Fixed Code
String url = request.getParameter("url");
if (!isUrlAllowed(url)) {
throw new SecurityException("URL not allowed");
}
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setConnectTimeout(5000);
con.setReadTimeout(5000);
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
private boolean isUrlAllowed(String url) {
List<String> allowedDomains = Arrays.asList("api.example.com", "cdn.example.com");
try {
URL u = new URL(url);
return allowedDomains.contains(u.getHost()) && u.getProtocol().equals("https");
} catch (MalformedURLException e) {
return false;
}
}
Fix Explanation
The vulnerable code accepts any URL without validation.The fix implements URL validation against a whitelist of allowed domains.Only HTTPS protocol is allowed.Timeouts are set to prevent hanging connections.
const url = req.query.url;
const allowedDomains = ['api.example.com', 'cdn.example.com'];
function isUrlAllowed(urlString) {
try {
const urlObj = new URL(urlString);
return allowedDomains.includes(urlObj.hostname) &&
urlObj.protocol === 'https:';
} catch {
return false;
}
}
if (!isUrlAllowed(url)) {
throw new Error('URL not allowed');
}
const response = await fetch(url, {
timeout: 5000,
follow: 1
});
const data = await response.json();
res.send(data);
Fix Explanation
The vulnerable code makes requests to any provided URL.The fix validates URLs against a whitelist of allowed domains.Only HTTPS protocol is allowed.Request timeout and redirect limits are set.
from urllib.parse import urlparse
import requests
ALLOWED_DOMAINS = ['api.example.com', 'cdn.example.com']
def is_url_allowed(url):
try:
parsed = urlparse(url)
return (parsed.scheme == 'https' and
parsed.netloc in ALLOWED_DOMAINS)
except:
return False
url = request.args.get('url')
if not is_url_allowed(url):
raise ValueError('URL not allowed')
response = requests.get(url,
timeout=5,
allow_redirects=False,
verify=True)
return response.content
Fix Explanation
The vulnerable code makes requests to any URL without validation.The fix implements URL validation with an allowed domains list.Only HTTPS is allowed.Timeouts and SSL verification are enforced.
Vulnerable Code
string url = Request.QueryString["url"];
using (var client = new HttpClient())
{
var response = await client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
Fixed Code
private static readonly HashSet<string> AllowedDomains =
new HashSet<string> { "api.example.com", "cdn.example.com" };
private static bool IsUrlAllowed(string url)
{
if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
{
return uri.Scheme == "https" &&
AllowedDomains.Contains(uri.Host);
}
return false;
}
string url = Request.QueryString["url"];
if (!IsUrlAllowed(url))
{
throw new SecurityException("URL not allowed");
}
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(5);
var response = await client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
Fix Explanation
The vulnerable code accepts any URL without validation.The fix implements URL validation against a whitelist.Only HTTPS URLs are allowed.Request timeout is configured.
The vulnerable code fetches any provided URL.The fix validates URLs against an allowed domains list.Only HTTPS is allowed.Timeout and redirect settings are configured.
The vulnerable code makes requests to any URL.The fix implements URL validation with allowed domains.Only HTTPS is allowed.Timeout and redirect policies are set.
Need more help in preventing SSRF?
Mobb supports fixing many forms of SSRF vulnerabilities, and can mitigate your issues in batch.