Server-Side Request Forgery

C# server-side request forgery

Description

Passing a user-supplied URL to a server-side request made with HttpClient, WebRequest, or a Uri-based API can let an attacker direct requests to internal services or metadata endpoints.

Potential impact

  • Internal network scanning, theft of cloud metadata, or calls to internal APIs.

Remediation

Prefer selecting destinations from a server-controlled mapping of identifiers to fixed URIs instead of accepting URLs or hosts directly. If arbitrary URLs are essential, strictly allow-list schemes, hosts, and ports; reject loopback, private, link-local, and metadata addresses across all DNS results; and disable automatic redirects or validate every redirect destination again.

Examples

Before

csharp
var response = await httpClient.GetAsync(url);

After

csharp
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

public sealed class StatusController : ControllerBase
{
    private static readonly IReadOnlyDictionary<string, Uri> Endpoints =
        new Dictionary<string, Uri>(StringComparer.Ordinal)
        {
            ["catalog"] = new Uri("https://catalog-api.example.com/health"),
            ["billing"] = new Uri("https://billing-api.example.com/health")
        };

    private static readonly HttpClient Client = new HttpClient(
        new HttpClientHandler { AllowAutoRedirect = false });

    [HttpGet("/status")]
    public async Task<IActionResult> GetStatus([FromQuery] string service)
    {
        if (service == null || !Endpoints.TryGetValue(service, out Uri endpoint))
        {
            return BadRequest("Unknown service");
        }

        using HttpResponseMessage response = await Client.GetAsync(endpoint);
        return StatusCode((int)response.StatusCode);
    }
}

Explanation:

  • Before: Sending a user-controlled URL to an outbound request API may enable SSRF.
  • After: Users select only a service identifier; the actual URI comes from a fixed mapping in server code. Unknown identifiers are rejected and automatic redirects are disabled, so neither user input nor redirects can introduce another destination.

References