11

The application lets users specify a URL for their profile picture. It fetches the data from the URL and saves it on the server. However, the app is vulnerable to server-side request forgery (SSRF) - you can specify URLs like file:///etc/passwd and also access local HTTP services like http://localhost:8080/.

What's the best way to fix this? Some ideas I had:

  • Restrict the URL protocol to HTTP and HTTPS.
  • DNS lookup the host name and check it's not a local address.
  • Disable redirects.

This seems a good start - although there's a TOCTOU issue with the DNS lookup (may be ok in practice, as local DNS will cache).

An alternative idea I had was to place a proxy in a restricted network segment, where it can only see the Internet, and send requests through that.

I did research this online, but there's not much information. This article is pretty good.

  • 2
    Using a segmented proxy server is a good idea. I answered a similar question here. DNS caching can be circumvented by building the request manually (i.e. explicitly send the request to the resolved IP address and set host header/the host used for SNI manually). – SilverlightFox May 18 '16 at 18:26
  • Thanks @SilverlightFox. Any tip on how to explicity send a request to specific resolved IP? I couldn't see how with java.net.URL – paj28 May 18 '16 at 20:30
  • See this answer - you can set the IP address as the host, then manually set the Host header. Of course for HTTPS connections you'll have to check that the API automatically uses your set Host header for the SNI sent during handshaking. – SilverlightFox May 19 '16 at 10:50
  • Would a whitelist/blacklist solution work, or is it too restrictive? For example, you could whitelist several known image sharing websites. Local servers (including localhost) in your company's domain could be blacklisted with the exception of say one server designated to share images. – HTLee Jun 18 '16 at 9:22
  • Also since your application is fetching images from other servers, a rate limiter to ensure the app doesn't flood the target URLs with requests could be important. You don't want your users, whether by accident or otherwise to launch a DoS attack against the URL they specify using your app. – HTLee Jun 18 '16 at 9:31
6
+50

This is the code I'm currently using:

if(!url.getProtocol().startsWith("http"))
    throw new Exception();
InetAddress inetAddress = InetAddress.getByName(url.getHost());
if(inetAddress.isAnyLocalAddress() || inetAddress.isLoopbackAddress() || inetAddress.isLinkLocalAddress())
    throw new Exception();
HttpURLConnection conn = (HttpURLConnection)(url.openConnection());
conn.setInstanceFollowRedirects(false);
conn.connect();
IOUtils.copy(conn.getInputStream(), out);

It enforces HTTP or HTTPS, forbids local addresses, and disables redirects. However, it still has the TOCTOU (time of check, time of use) flaw.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.