Request throttling in .NET Core MVC

Security in APIs is important and we might not want the APIs we build to be overly used. I built a small attribute function that allows for throttling of a specific endpoint.

APISecurityTutorials
Request Throttling in .NET Core MVC

Why do I need to throttle usage?

Security in APIs is important and we might not want the APIs we build to be overly used. This could be to prevent DDoS attacks or to make sure no one tries to brute-force-use your API. To solve this problem I built a small attribute function that allows for throttling of a specific endpoint.

When I started writing this I got a lot of inspiration from this post on stack overflow.

Attribute code

Here is the code for the throttling attribute

1[AttributeUsage(AttributeTargets.Method)]
2public class ThrottleAttribute : ActionFilterAttribute
3{
4 public string Name { get; set; }
5 public int Seconds { get; set; }
6 public string Message { get; set; }
7
8 private static MemoryCache Cache { get; } = new MemoryCache(new MemoryCacheOptions());
9
10 public override void OnActionExecuting(ActionExecutingContext c)
11 {
12 var key = string.Concat(Name, "-", c.HttpContext.Request.HttpContext.Connection.RemoteIpAddress);
13
14 if (!Cache.TryGetValue(key, out bool entry))
15 {
16 var cacheEntryOptions = new MemoryCacheEntryOptions()
17 .SetAbsoluteExpiration(TimeSpan.FromSeconds(Seconds));
18
19 Cache.Set(key, true, cacheEntryOptions);
20 }
21 else
22 {
23 if (string.IsNullOrEmpty(Message))
24 Message = "You may only perform this action every {n} seconds.";
25
26 c.Result = new ContentResult {Content = Message.Replace("{n}", Seconds.ToString())};
27 c.HttpContext.Response.StatusCode = (int) HttpStatusCode.Conflict;
28 }
29 }
30}

Example usage

1[Route("api/[controller]")]
2public class ActionsController : Controller
3{
4 // GET /api/actions/throttle
5 [HttpGet("throttle")]
6 // Only allow access every 5 seconds
7 [Throttle(Name = "ThrottleTest", Seconds = 5)]
8 public object GetThrottle() => new
9 {
10 Message = "OK!"
11 };
12}
Share to: