Reputation: 5265
I have a few Web API
endpoints with no authentication/authorization since it could be used for guest users as well. These endpoints will be consumed directly through XHR/Ajax/JS
. However, i would like to allow the request from only a few origins. For this, i've used the Cors
middleware like below:
ConfigureServices Method
services.AddCors(options =>
{
options.AddPolicy("AllowSpecific", builder =>
builder.WithOrigins("http://localhost:55476")
.AllowAnyHeader()
.AllowAnyMethod());
});
Configure Method
app.UseCors("AllowSpecific");
This restriction works for requests coming from browsers. However, if the request is coming from Http Clients such as Postman
, Fiddler
, etc., the request goes through.
Is there any way to tackle such scenarios?
Upvotes: 3
Views: 1599
Reputation: 5265
For lack of a better alternative for now, i've replaced CORS
middleware with a custom middleware which will check each request's header Origin
and allow/restrict based on configuration. This works both for cross-browser requests and HTTP Client requests.
Middleware
public class OriginRestrictionMiddleware
{
private readonly RequestDelegate _next;
private readonly IConfiguration _configuration;
private readonly ILogger _logger;
public OriginRestrictionMiddleware(RequestDelegate next, IConfiguration configuration, ILoggerFactory loggerFactory)
{
_next = next;
_configuration = configuration;
_logger = loggerFactory.CreateLogger<OriginRestrictionMiddleware>();
}
public Task Invoke(HttpContext context)
{
try
{
var allowedOriginsConfig = _configuration.GetSection("AllowedOrigins").Value;
var allowedOrigins = allowedOriginsConfig.Split(',');
_logger.LogInformation("Allowed Origins: " + allowedOriginsConfig);
var originHeader = context.Request.Headers.Where(h => h.Key == "Origin");
if (originHeader.Any())
{
var requestOrigin = originHeader.First().Value.ToString();
_logger.LogInformation("Request Origin: " + requestOrigin);
foreach (var origin in allowedOrigins)
{
//if(origin.StartsWith(requestOrigin))
if (requestOrigin.Contains(origin))
{
return _next(context);
}
}
}
context.Response.StatusCode = 401;
return context.Response.WriteAsync("Not Authorized");
}
catch(Exception ex)
{
_logger.LogInformation(ex.ToString());
throw;
}
}
}
public static class OriginRestrictionMiddlewareExtension
{
public static IApplicationBuilder UseOriginRestriction(this IApplicationBuilder builder)
{
return builder.UseMiddleware<OriginRestrictionMiddleware>();
}
}
Startup Configuration
app.UseOriginRestriction();
AppSettings.json
"AllowedOrigins": "http://localhost:55476,http://localhost:55477,chrome-extension"
chrome-extension
entry is there to allow request from Postman
during development. It will be removed when deployed to server.
I suspect that this solution can also be bypassed one way or another. However, i'm hoping it will work for most of the cases.
Upvotes: 1