ASP.NET Core Secure Public APIs
ASP.NET Core is a popular framework. Key benefits include features like cross-platform execution, high-performance, built-in Dependency Injection and modular HTTP request pipeline.
The challenge
ASP.NET Core provides support for many authentication providers to secure the app through numerous authentication workflows. However, in many scenarios, we have to provide a web application/site that relies on unauthenticated APIs with anonymous access.
For example, we have a list of products in a database and we want to display these products on a web page. We may write an API to provide the list of products and have the front end (web site) retrieve this list via the API and display them on our public products web page.
Without applying a level of security, such architectures can be a security vulnerability open for exploitation.
Available Security Controls in ASP.NET
ASP.NET Core provides a solution for common vulnerabilities, including,
- Cross-Site Scripting
- SQL Injection,
- Cross-Site Request Forgery (CSRF)
- Open redirects
Going a step further
As a developer, we should also protect our apps from other common attack vectors, including,
- Distributed denial-of-service (DDOS)
- Denial-of-service (DOS)
- Bulk data egress
- Probe response
- Scraping
Two steps we can take are referer header checks and rate-limiting, discussed in detail below.
Use an IP Based Request Limit Action Filter
We can limit clients to a number of request within the specified time span to prevent malicious bot attacks. I have created an IP Based Request Limit Action Filter in ASP.NET Core. Do be aware that multiple clients may sit behind one IP address so you may want to cater for this in your limits, or combine the IP address with other request data to make requests more unique.
In order to yse the filter, you just need to add ActionAttribute on top of Controller Action.
- [HttpGet()]
- [ValidateReferrer]
- [RequestLimit("Test-Action", NoOfRequest = 5, Seconds = 10)]
- public async Task<ActionResult> GetAsync(CancellationToken ct)
- {
- // code here
- }
Here is the implementation of the filter,
- namespace Security.Api.Filters {
- using System;
- using System.Net;
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.AspNetCore.Mvc.Filters;
- using Microsoft.Extensions.Caching.Memory;
- /// <summary>
- /// Action filter to restrict limit on no. of requests per IP address.
- /// </summary>
- /// <seealso cref="Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute" />
- [AttributeUsage(AttributeTargets.Method)]
- public class RequestLimitAttribute: ActionFilterAttribute {
- public RequestLimitAttribute(string name) {
- Name = name;
- }
- public string Name {
- get;
- }
- public int NoOfRequest {
- get;
- set;
- } = 1;
- public int Seconds {
- get;
- set;
- } = 1;
- private static MemoryCache Cache {
- get;
- } = new MemoryCache(new MemoryCacheOptions());
- public override void OnActionExecuting(ActionExecutingContext context) {
- var ipAddress = context.HttpContext.Request.HttpContext.Connection.RemoteIpAddress;
- var memoryCacheKey = $ "{Name}-{ipAddress}";
- Cache.TryGetValue(memoryCacheKey, out int prevReqCount);
- if (prevReqCount >= NoOfRequest) {
- context.Result = new ContentResult {
- Content = $ "Request limit is exceeded. Try again in {Seconds} seconds.",
- };
- context.HttpContext.Response.StatusCode = (int) HttpStatusCode.TooManyRequests;
- } else {
- var cacheEntryOptions = new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(Seconds));
- Cache.Set(memoryCacheKey, (prevReqCount + 1), cacheEntryOptions);
- }
- }
- }
- }
Add Referer Check Action Filter
To protect APIs from abuse and to provide additional protection against Cross-Site Request Forgery (CSRF) attacks, a security check is performed on the request Referer header for every REST API request sent to the server.
This validates where the API request has come from. I have created a Referer Check Action Filter in ASP.NET Core. It also prevents access from tools like POSTMAN, REST Client etc.
You just need to add ActionAttribute on top of Controller Action.
- [HttpGet()]
- [ValidateReferrer]
- public async Task<ActionResult> GetAsync(CancellationToken ct)
- {
- // your code here
- }
Here is the implementation of the filter,
Sébastien SougnezPosted Mar 22, 2021, 6:35 PM
The referer action filter is pretty useless as it is possible to define this header in POSTMAN
Laxmidhar SahooPosted May 26, 2020, 4:45 AM
Thanks for a usefull article