I want a server application to send webhooks (i.e. outgoing http-post requests) to user controlled http(s) urls. A naive implementation of that functionality is vulnerable to server-side request forgery (SSRF), since the target host could be within the same private network as the server. To prevent that, I would like to blacklist private IP addresses.
In classic .net HttpWebRequest
supported this via the ServicePoint.BindIPEndPointDelegate
, which received the IP address the client connects to. However in .NET Core, HttpWebRequest
was turned into a wrapper over HttpClient
, and this callback is ignored completely. This introduces an SSRF vulnerability into previously secure applications.
But even migrating from the deprecated using HttpWebRequest
to using HttpClient
directly doesn’t appear to help. I could not find any callback in HttpClientHandler
that received the IP address before connecting to it.
Resolving the domain to an IP address before passing the original URL to HttpClient
doesn’t work reliably either. This is complex, since it needs to handle multiple returned IP addresses, and it’s vulnerable to ToC/ToU, since the name resolution might return a different response for the check and the request execution.
Another idea is to resolve the domain, fill the host-to-connect-to with the IP and and the original domain in the-http host header (if HttpClient
even supports that). This also requires manual handling of HTTP redirects, making it complex and fragile.
There is also the option to handle it outside the application (via proxies, firewalls, etc.), but that doesn’t feel like a clean solution either, and increases infrastructure cost and complexity.
Is there a reasonable way to support sending webhooks using HttpClient
without suffering for SSRF?