Server-side request forgery (SSRF) - C-Sharp

Server-side request forgery (SSRF) - C-Sharp

Need

Mitigation of server-side request forgery (SSRF) attacks

Context

  • Usage of C# for developing robust and scalable applications
  • Usage of System for low-level operations and platform-specific functionality
  • Usage of System.Net.Http for making HTTP requests in .NET development
  • Usage of Microsoft.AspNetCore.Mvc for building web applications with ASP.NET Core MVC

Description

Non compliant code

        using System;
using System.Net.Http;
using Microsoft.AspNetCore.Mvc;

namespace VulnerableApp.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
public class SSRFController : ControllerBase
    {
        [HttpGet]
        public async Task Get(string url)
        {
            using (var httpClient = new HttpClient())
            {
                var response = await httpClient.GetAsync(url);
                return await response.Content.ReadAsStringAsync();
            }
        }
    }
}
        
        

The above code snippet represents a simple ASP.NET Core controller that accepts a URL as a parameter and makes a GET request to that URL. The response from this request is then returned to the client.

This is a classic example of a Server-Side Request Forgery (SSRF) vulnerability. An attacker can exploit this vulnerability by providing a URL that leads to an internal resource, which the server has access to but should not be exposed to the client. For example, an attacker could provide a URL to an internal service, a file on the server, or even cloud metadata services, causing the server to retrieve and return sensitive information.

The vulnerability lies in the Get method, which accepts any URL and makes a request to it without any validation or restriction. This means that an attacker can make the server perform requests to arbitrary domains, potentially leading to data exposure, service disruption, or other security issues.

Steps

  • Validate the input: Implement input validation to ensure that the 'url' parameter is a valid and trusted URL. Use a whitelist approach to only allow specific domains or URLs.
  • Implement a URL validation mechanism: Use a regular expression or a library function to validate the format and structure of the URL. This helps prevent any malicious or malformed URLs from being processed.
  • Implement a URL filtering mechanism: Use a URL filtering mechanism to restrict the allowed domains or URLs that the application can make requests to. This can be done by maintaining a whitelist of trusted domains or URLs and only allowing requests to those.
  • Implement a DNS resolution mechanism: Instead of directly using the user-provided URL, implement a mechanism to resolve the domain name from the URL and validate it against a whitelist of trusted domains. This helps prevent any DNS-based attacks or IP address manipulation.
  • Use a proxy server: Consider using a proxy server to handle all outgoing requests from the application. This can help add an additional layer of security by filtering and validating the requests before they are sent to external domains.
  • Implement rate limiting: Implement rate limiting to prevent abuse or excessive requests to external domains. This can help mitigate the impact of any potential SSRF attacks.
  • Educate developers: Provide training and awareness to developers about the risks and best practices for preventing SSRF vulnerabilities. This includes understanding the impact of SSRF, proper input validation, and secure coding practices.

Compliant code

        using System;
using System.Net.Http;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;

namespace VulnerableApp.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class SSRFController : ControllerBase
    {
        private static readonly Regex urlRegex = new Regex(@"^https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)$");
        private static readonly HashSet whitelist = new HashSet { "trusteddomain1.com", "trusteddomain2.com" };

        [HttpGet]
        public async Task Get(string url)
        {
            if (string.IsNullOrEmpty(url) || !urlRegex.IsMatch(url) || !IsWhitelisted(url))
            {
                return "Invalid or untrusted URL";
            }

            using (var httpClient = new HttpClient())
            {
                var response = await httpClient.GetAsync(url);
                return await response.Content.ReadAsStringAsync();
            }
        }

        private bool IsWhitelisted(string url)
        {
            var uri = new Uri(url);
            return whitelist.Contains(uri.Host);
        }
    }
}
        
        

The updated code includes several measures to mitigate the Server-side Request Forgery (SSRF) vulnerability:

1. Input Validation: The code checks if the 'url' parameter is null or empty. If it is, the function returns an error message.

2. URL Validation: The code uses a regular expression to validate the format and structure of the 'url' parameter. If the URL does not match the regular expression, the function returns an error message.

3. URL Filtering: The code checks if the domain of the 'url' parameter is in a whitelist of trusted domains. If it is not, the function returns an error message. This is done in the IsWhitelisted function, which extracts the host from the URL and checks if it is in the whitelist.

These measures ensure that the application only makes requests to valid and trusted URLs, preventing SSRF attacks.

Please note that this code does not include all the recommended measures, such as using a proxy server, implementing rate limiting, or providing training to developers. These measures should be implemented as part of the application's overall security strategy.

References