SV.SSRF.URI
URI based on invalidated user input.
The SV.SSRF.URI checker flags cases where the Java web server application receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
As of release 2023.2, this checker supports Jakarta EE.
Vulnerability and risk
Server-Side Request Forgery (SSRF) is an attack vector that abuses an application to interact with the internal or external network or the machine itself. One of the enablers for this vector is the mishandling of different types of URLs, for example:
- image files on a external server, for example, a user enters a URL to an image of their avatar for an application to download and use.
- custom webhooks, where users specify webhook handlers or callback URLs.
-
internal requests to interact with another service to serve a specific function. Frequently, user data is sent for processing, and, if poorly handled, can result in injection attacks.
Note that SSRF is not limited to the HTTP protocol. Generally, the first request is HTTP, but in cases where the application itself performs the second request, it can use different protocols, for example, FTP, SMB, SMTP) or schemes such as file://, phar://, gopher://, data://, dict://,and so on.
If an application is vulnerable to XML eXternal Entity (XXE) injection, then it can be exploited to perform a SSRF attack
Mitigation and prevention
Ensure that the IP address provided belongs to one of the IP addresses of the identified and trusted applications.
Vulnerable code example
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
public class SV_SSRF_URI_POSITIVE_JAKARTA {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,URISyntaxException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
String url = req.getParameter("uri");
URI uri = new URI(url);
// BAD: a request parameter is incorporated without validation into a Http request
HttpRequest r = HttpRequest.newBuilder(uri).build();
client.send(r, null);
}
}
In this example, the String URL parameter that is extracted from the HttpServletRequest by using the req.getParameter("uri") is being used for the HttpRequest connection without any validation. Klocwork reports a defect on line 13, indicating, "Invalidated user input used as a part of URI object."
Fixed code example
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
public class SV_SSRF_URI_POSITIVE_JAKARTA {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, URISyntaxException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
// GOOD: the request parameter is validated against a known fixed string or valid source of IP address
String url = req.getParameter("uri");
if (VALID_URI.equals(url)) {
URI uri = new URI(url);
HttpRequest r = HttpRequest.newBuilder(uri).build();
client.send(r, null);
}
}
In this fixed example, Klocwork no longer reports a defect because the URL parameter that is extracted from HttpServletRequest by using req.getParameter("uri") is validated against a trusted URL before being used for the HttpRequest connection.
External guidance
Security training
Application security training materials provided by Secure Code Warrior.
Extension
This checker can be tuned to check whether a user is authorized to access protected APIs that are used in the project. You can do this by using the @CheckerParam option in a .jkb file. See Tuning Java analysis for more information.