Prevention of unauthorized server-side requests to arbitrary domains
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SSRFServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse res) {
try {
String url = req.getParameter("url");
URL obj = new URL(url);
BufferedReader in = new BufferedReader(new InputStreamReader(obj.openStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
res.getWriter().write(response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
The above code is an example of a Server-Side Request Forgery (SSRF) vulnerability. It is a servlet that takes a URL parameter from the HTTP request and makes a request to that URL. After that, it reads the response from the requested URL and writes it back to the HTTP response.
Here is how the vulnerability works:
- The
doGet
method of the servlet is called when an HTTP GET request is made to the servlet.
- The
req.getParameter("url")
line gets the value of the "url" parameter from the HTTP request. This value is controlled by the user, who can enter any URL.
- The
new URL(url)
line creates a URL object from the user-controlled string. This URL object is used to make a request to the specified URL.
- The
obj.openStream()
method opens a connection to the URL and returns an input stream for reading from that connection.
- The following lines read the response from the URL and append it to a
StringBuffer
object.
- The
res.getWriter().write(response.toString())
line writes the response back to the HTTP response.
The vulnerability lies in the fact that the application server makes a request to an arbitrary URL specified by the user. An attacker can exploit this to make the server request a malicious URL, potentially leading to data exposure, denial of service, or other impacts.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SSRFServlet extends HttpServlet {
private static final List WHITELISTED_DOMAINS = Arrays.asList("http://example.com", "http://example2.com");
protected void doGet(HttpServletRequest req, HttpServletResponse res) {
try {
String url = req.getParameter("url");
URL obj = new URL(url);
// Validate the URL
if (!WHITELISTED_DOMAINS.contains(obj.getHost())) {
throw new IllegalArgumentException("Invalid URL");
}
BufferedReader in = new BufferedReader(new InputStreamReader(obj.openStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
res.getWriter().write(response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
The updated code includes a whitelist of allowed domains. When a GET request is made, the URL provided by the user is checked against this whitelist. If the URL's host is not in the whitelist, an
IllegalArgumentException
is thrown, and the request is not processed.
This approach prevents Server-Side Request Forgery (SSRF) by ensuring that the server only makes requests to trusted domains. It is a simple and effective way to mitigate the risk of SSRF attacks.
However, this is just one layer of defense. To further secure your application, consider implementing additional measures such as rate limiting, strong access controls, and regular software updates. Also, monitor and log requests to detect and investigate any suspicious activity.