There are several ways to restrict access to a Web server based on the requestor’s IP address. We can do that from IIS or using inbound Firewall rules. But If you want to restrict access to one of the applications deployed in the server based on the IP Address then you have to achieve that programmatically. In this post, I will guide you on how to restrict IP address in ASP.NET Core
Check this post for restricting IP Address in classic ASP.NET Web API
We will discuss the following in this post
- What is Whitelist and Blacklist and how to configure and read it from appsettings.json
- Writing a Middleware to implement IP Filtering
- Recommended readings and courses
Whitelist vs Blacklist
To provide access or deny, we have to get the IP Address of the incoming request. We need to verify that against a list. When I say list, you can use this list to grant or deny access. If you use the list to grant access, it is called Whitelist else it is called Blacklist.
- Whitelisting – Allow traffic only to known addresses
- Blacklisting – Deny traffic to known addresses
For this example, I am going to use a whitelist of IP Address and use middleware to provide access only to the IP Address I have configured. I have the list of IP Addresses stored in an array format inside “ApplicationOptions” in the appsettings.json. Alternatively, we can use a table-driven approach that allows the admin to add update entries easily.
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ApplicationOptions": {
"Whitelist": [ "172.0.0.1", "::1" ]
}
}
How to read values from appsettings.json?
The package Microsoft.Extensions.Options
comes in handy for reading the values from appsettings.json
and inject into the configuration
class. To do that we need to have a model class for ApplicationOptions
and the ConfigureServices
method of Startup
class similar to the one below.
public void ConfigureServices(IServiceCollection services)
{
// Inject Application Options
services.Configure<ApplicationOptions>(Configuration.GetSection("ApplicationOptions"));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
public class ApplicationOptions
{
public Lis<string> Whitelist { get; set; }
}
What is middleware?
ASP.NET Core request pipeline consists of a series of request delegates that are chained together. The first one receives an HTTP request, does some processing, and gives the request to the next. However, at any point, a request delegate can decide to take action and process the request returning the response without passing to the next one.
IP Filter Middleware:
Following is the code for the IP Filter Middleware
public class IPFilter
{
private readonly RequestDelegate _next;
private readonly ApplicationOptions _applicationOptions;
public IPFilter(RequestDelegate next, IOptions<ApplicationOptions> applicationOptionsAccessor)
{
_next = next;
applicationOptions = applicationOptionsAccessor.Value;
}
public async Task Invoke(HttpContext context)
{
var ipAddress = context.Connection.RemoteIpAddress;
List<string> whiteListIPList = _applicationOptions.Whitelist;
var isInwhiteListIPList = whiteListIPList
.Where(a => IPAddress.Parse(a)
.Equals(ipAddress))
.Any();
if (!isInwhiteListIPList)
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return;
}
await _next.Invoke(context);
}
}
We have to write an extension method to add the middleware to the HTTP request pipeline
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseIPFilter(this IApplicationBuilder builder)
{
return builder.UseMiddleware<IPFilter>();
}
}
Once we are done with the middleware and the extension, we have to register the middleware in the Configure
method of Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIPFilter();
app.UseMvc();
}
Okay, now there are other questions
- Do I need to enable this IP restriction for the entire application only?
- What if I want to restrict only for a certain controller or action?
Please refer the following link to enable authorization on controller or action level
Policy-based authorization in ASP.NET Core
Summary
This article tried to provide a summary of the very unique requirement of implementing security to Web API by IP Address. We discussed the basic concepts, Middleware and an implementation example with ASP.NET Web API.
The full implementation of this post can be found in Github
Recommended Courses
- Designing RESTful Web APIs
- Documenting an ASP.NET Core API with OpenAPI / Swagger
- Using OpenAPI/Swagger for Testing and Code Generation in ASP.NET Core
We may receive a commission for purchases made through these links.
Further Reading
You can refer to the following link if you want to learn more about Web API Security.
Pingback: Restrict IP Address in ASP.NET Web API - Blog of Pi
Hello,
very good contribution. I would like to know how a global blacklist and whitelist can be implemented for just a single controller. Can you help me with this?
Thanks and kind regrds
fs
Please check this
https://www.blogofpi.com/policy-based-authorization-in-asp-net-core/
Works fine when the Web API app is running locally, but why does this throw the HttpStatusCode 403 code when it’s published to Azure App Services?
I have a separate Frontend application, which is currently running and being tested locally on a different port and it is receiving the 403 code. Debug logs in Azure are just stating that the request is forbidden.
The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it. A 403 response is not a case of insufficient client credentials; that would be 401 (“Unauthorized”). REST APIs use 403 to enforce application-level permissions. For example, a client may be authorized to interact with some, but not all of a REST API’s resources. If the client attempts a resource interaction that is outside of its permitted scope, the REST API should respond with 403.
Please refer
https://stackoverflow.com/questions/3297048/403-forbidden-vs-401-unauthorized-http-responses
https://stackoverflow.com/questions/50143518/401-unauthorized-vs-403-forbidden-which-is-the-right-status-code-for-when-the-u
Thanks for the article. Typo in ApplicationOptions.cs, missing T in List
“public Lis Whitelist { get; set; } “
Thank you very much!
I did find the extension method part a bit redundant and just skipped it and also you can just use “Any” with predicate, rather than “Where” and then “Any” but all in all, very helpful 🙂
Very good article, thank you 🙂
Very good article, thanks for sharing 🙂
Very helpful, thanks.