In the last example, we saw how we could access a “protected” endpoint by exploiting a server-side request forgery (SSRF). Let’s look at a safer app version with the SSRF vulnerability removed. While the
/admin endpoint still uses the localhost IP for access control, by removing the SSRF we reduce the overall risk of authorized users accessing the protected endpoint.
Looking back at the
/ssrf endpoint, we see several new lines of code added to the method call. Below the
url parameter component, we now have an array called
safe_host. This array contains an entry for a predetermined host, which we have deemed safe. We also have a
safe_content_type parameter which defines a list of content types we have chosen to allow in the request responses. From here, we can use these features, in this case, just the
safe_host list, to determine if a requested URL is allowed.
By implementing an allow list, we can help ensure that the requests our server sends do not go to unexpected and potentially dangerous places, such as the
/admin endpoint. It is worth noting here, however, that this safety measure may not be enough in some situations. For example, if the application was set to follow redirects, and an open redirect vulnerability was uncovered in the “safe” host, it may still be possible to make arbitrary requests to a dangerous location!
Overall, SSRF is an incredibly dangerous vulnerability, which generally requires a layered approach for protection. When securing your application against SSRF, we should consider the following solutions:
- Apply an allow list to restrict arbitrary requests.
- Ensure “protected” assets have robust access controls spanning past just IPs.
Try to bypass the security for the patched website by inserting the following:
https://127.0.0.1:8181/admin within the ‘url’ parameter in the URL. Your URL should look like the following: