Limit access to your ASP.NET Core app by IP address with middleware

Update 12 Sep 2017: You can add IP restrictions to your Web App from Azure Portal now. https://docs.microsoft.com/en-us/azure/app-service/app-service-ip-restrictions

I’m working on a mini-project that should be seen only from inside our company network. This is my first ASP.NET Core project and I’m still kind of lost with the configuration part and there aren’t many examples in stackoverflow how to do this or that with ASP.NET Core. However I managed to do IP restrictions for my ASP.NET Core app running on Azure and here is how I did it.

App settings

First off let’s put the allowed IP addresses in our appsettings.json by adding a new section called “IpSecuritySettings”:

"IpSecuritySettings": {
    "AllowedIPs": "0.0.0.0,127.0.0.1" // comma-delimited list of whitelisted IP addresses
}

Create Configuration-folder to your project root and add a file called IpSecuritySettings.cs there:

public class IpSecuritySettings  
{
    public string AllowedIPs { get; set; }
    public List<string> AllowedIPsList {
        get { return !string.IsNullOrEmpty(AllowedIPs) ? AllowedIPs.Split(',').ToList() : new List<string>(); }
    }
}

Use Middleware to check if visitor’s IP is whitelisted

Middleware are software components that are assembled into an application pipeline to handle requests and responses. Each component chooses whether to pass the request on to the next component in the pipeline, and can perform certain actions before and after the next component is invoked in the pipeline. Request delegates are used to build the request pipeline. The request delegates handle each HTTP request.

https://docs.asp.net/en/latest/fundamentals/middleware.html#what-is-middleware

Let’s start by creating a class called IpRestrictionMiddleware.cs:

public class IpRestrictionMiddleware  
{
    public readonly RequestDelegate Next;
    public readonly IpSecuritySettings IpSecuritySettings;

    public IpRestrictionMiddleware(RequestDelegate next, IOptions<IpSecuritySettings> ipSecuritySettings)
    {
        Next = next;
        IpSecuritySettings = ipSecuritySettings.Value;
    }

    public async Task Invoke(HttpContext context)
    {
        var ipAddress = (string)context.Connection.RemoteIpAddress?.ToString();
        if (!IpSecuritySettings.AllowedIPsList.Contains(ipAddress))
        {
            context.Response.StatusCode = 403;
            return;
        }

        await Next(context);
    }
}

Now we have the Middleware and the only thing we still have to do is hook the middleware to our request pipeline in Startup.cs:

Make your IpSecuritySettings injectable by adding the following line in ConfigureServices-method:

public void ConfigureServices(IServiceCollection services)  
{
    ...

    // IP Security settings
    services.Configure<IpSecuritySettings>(Configuration.GetSection("IpSecuritySettings"));
}

Hook IpRestrictionMiddleware to the request pipeline by adding the following line in Configure-method:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        ...
    }
    else
    {
        app.UseMiddleware<IpRestrictionMiddleware>();
        ...
    }

     ...
}

Note! The order in which you add middleware components is generally the order in which they take effect on the request, and then in reverse for the response. To ensure IpRestrictionMiddleware is used on every request you need to put the registration of IpRestrictionMiddleware before any other middleware that terminates the pipeline, such as Mvc.