We have been looking a lot on StackOverflow for this but we cannot seem to have it working.
Our scenario is as following. We have server A and server B. Server A is a web API that communicates with Server B which is also a web API. Server B should ONLY serve http requests comming from server A and deny all other requests. We are trying to force this by using cors
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: "AllowSpecificOrigin", builder =>
{
builder.WithOrigins(new string[0]); // Empty list as a test.
});
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
{
app.UseRouting();
app.UseCors("AllowSpecificOrigin");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
...
}
But now in one of our controllers, there are two methods. One that requires CORS and one that doesn't.
[ApiController]
[Route("api/Server")]
public sealed class ServerController : ControllerBase
{
[HttpGet]
[Route("ServerCheck")]
[DisableCors]
public IActionResult ServerCheck()
{
return Ok(true);
}
[HttpGet]
[Route("Version")]
[EnableCors("AllowSpecificOrigin")]
public IActionResult Version()
{
return Ok(GetType().Assembly.GetName().Version.ToString());
}
}
If I know issue a request through Postman to both methods, both methods supply an answer. But since we did not allow any origin, how come our request is served in the controller?
Is CORS the wrong way to tackle this issue? What whould be the best way? Or is our configuration simply wrong?
Nowhere in our appsettings.json or appsettings.Development.json is there a line 'AllowedHosts'.
CodePudding user response:
You could create a custom authorization filter which validates that the host is allowed via an authorization filter
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
public class ValidateDomainAttribute : Attribute, IAuthorizationFilter
{
private IEnumerable<string> AllowedDomains { get; }
public ValidateDomainAttribute(params string[] domains){
AllowedDomains = domains;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var host = context.HttpContext.Request.Host;
if (!AllowedDomains.Contains(host, StringComparer.OrdinalIgnoreCase))
{
context.Result = new BadRequestObjectResult("Domain is not allowed !");
}
}
}
And to apply this globally for all controllers and actions by registering this attribute in the StartUp class:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.Filters.Add(new ValidateDomainAttribute("your-allowed-domain-1", "your-allowed-domain-2");
)};
// rest of code
}
}
More about filter attributes can be found here: https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-5.0
CodePudding user response:
Have you considered an IP Address allow list? Or an API Key or some other form of authentication?
It seems as if you are trying to leverage CORS for access control which is not it's purpose. The Mozilla Docs are pretty good, but the short version is that CORS is a way to safely get around the browser same origin restrictions and you should not expect it to work in the same way using Postman or any other non-browser client.
It is also worth considering that every header can be controlled by an attacker and so shouldn't be trusted and any credentials should be transmitted only via https