I am using API Gateway Pattern
in a Micro services
architecture in which the Front End Angular app
makes an HTTP request
to my API Gateway
project which is simply a ASP.net Core 3.1 Web API
project. Currently I only have 2 micro services
and an API Gateway
and all of them are of type ASP.net Core 3.1 Web API
project. The API Gateway
project has all the controllers of my micro services
. The purpose of the API Gateway
is just to receive the request from Front end
and make an HTTP Request
to the appropriate Micro service
.
Now in the AccountController.cs
of my API Gateway
project, I have the following code
/// <summary>
/// Gets the detail of an account by its id
/// </summary>
/// <param name="organizationId">Id of the Organization of which the account belongs to</param>
/// <param name="accountId">Id of Account of which information is being requested</param>
/// <returns>Account's Details</returns>
[HttpGet("{organizationId}/{accountId}")]
public async Task<IActionResult> GetAccountAsync(Guid organizationId, Guid accountId)
{
_uri = new Uri(uriString: $"{_configurationService.AccountAPI}GetAccount/{organizationId}/{accountId}");
using var result = await _client.GetAsync(_uri);
var content = await result.Content.ReadAsStringAsync();
return Ok(content.AsObject<MessageResponse<AccountDetailVM>>());
}
After searching about the SSRF
issue on stackoverflow I found the following recommendation at Veracode community.
Veracode Static Analysis will report a flaw with CWE 918 if it can detect that data from outside of the application (like an HTTP Request from a user, but also a file that may have been uploaded by a user, database data, webservice data, etc) is able to change the nature of a network request.
On Stackoverflow I found the following fix
For CWE ID 918 it is hard to make Veracode recognize your fix unless you have static URL. You need to validate all your inputs that become parts of your request URL.
That means I had to sanitize my input parameters OrganizationId
and AccountId
before appending them to the request URL.
Also another question on the veracode community suggested
The only thing that Veracode Static Analysis will automatically detect as a remediation for this flaw category is to change the input to be hardcoded
and they proposed a solution for the query string
The given example appears to take a model identifier and put it in the URL used in an internal request. We would recommend validating the ID per the rules you have for this datatype (typically this should only be alphanumeric and less than 255 characters) and URLencode it before appending it to a URL.
After all those stuff, I have made the following changes to my code
Here is the code after changes
/// <summary>
/// Gets the detail of an account by its id
/// </summary>
/// <param name="organizationId">Id of the Organization of which the account belongs to</param>
/// <param name="accountId">Id of Account of which information is being requested</param>
/// <returns>Account's Details</returns>
[HttpGet("{organizationId}/{accountId}")]
public async Task<IActionResult> GetAccountAsync(Guid organizationId, Guid accountId)
{
if (organizationId != Guid.Empty && accountId != Guid.Empty)
{
string url = HttpUtility.UrlEncode($"{_configurationService.AccountAPI}GetAccount/{organizationId}/{accountId}");
using var result = await _client.GetAsync(url);
var content = await result.Content.ReadAsStringAsync();
return Ok(content.AsObject<MessageResponse<AccountDetailVM>>());
}
return BadRequest();
}
Thats All I could do to sanitize my input parameters OrganizationId
and AccountId
but after all those changes veracode
still identifies a SSRF
flaw on line
using var result = await _client.GetAsync(url);
I found a hack to fix this issue, I just appended the query string parameters to the Base Address of httpClient and veracode
stopped giving me error.
Here is how the solution looks like
/// <summary>
/// Gets the detail of an account by its id
/// </summary>
/// <param name="organizationId">Id of the Organization of which the account belongs to</param>
/// <param name="accountId">Id of Account of which information is being requested</param>
/// <returns>Account's Details</returns>
[HttpGet("{organizationId}/{accountId}")]
public async Task<IActionResult> GetAccountAsync(Guid organizationId, Guid accountId)
{
if (organizationId != Guid.Empty && accountId != Guid.Empty)
{
var httpClient = new HttpClient();
//Appended the parameters in base address to
//to fix veracode flaw issue
httpClient.BaseAddress = new Uri($"{_configurationService.AccountAPI}GetAccount/{organizationId}/{accountId}");
//passing empty string in GetStringAsync to make sure
//veracode doesn't treat it like modifying url
var content = await httpClient.GetStringAsync("");
return Ok(content.AsObject<MessageResponse<AccountDetailVM>>());
}
return BadRequest();
}