Giter VIP home page Giter VIP logo

webapithrottle's Introduction

WebApiThrottle

Build status NuGet

ASP.NET Web API Throttling handler, OWIN middleware and filter are designed to control the rate of requests that clients can make to a Web API based on IP address, client API key and request route. WebApiThrottle package is available on NuGet at nuget.org/packages/WebApiThrottle.

Web API throttling can be configured using the built-in ThrottlePolicy. You can set multiple limits for different scenarios like allowing an IP or Client to make a maximum number of calls per second, per minute, per hour per day or even per week. You can define these limits to address all requests made to an API or you can scope the limits to each API route.


If you are looking for the ASP.NET Core version please head to AspNetCoreRateLimit project.

AspNetCoreRateLimit is a full rewrite of WebApiThrottle and offers more flexibility in configuring rate limiting for Web API and MVC apps.


Global throttling based on IP

The setup bellow will limit the number of requests originated from the same IP. If from the same IP, in same second, you'll make a call to api/values and api/values/1 the last call will get blocked.

public static class WebApiConfig
{
	public static void Register(HttpConfiguration config)
	{
		config.MessageHandlers.Add(new ThrottlingHandler()
		{
			Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, perHour: 200, perDay: 1500, perWeek: 3000)
			{
				IpThrottling = true
			},
			Repository = new CacheRepository()
		});
	}
}

If you are self-hosting WebApi with Owin, then you'll have to switch to MemoryCacheRepository that uses the runtime memory cache instead of CacheRepository that uses ASP.NET cache.

public class Startup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        // Configure Web API for self-host. 
        HttpConfiguration config = new HttpConfiguration();

        //Register throttling handler
        config.MessageHandlers.Add(new ThrottlingHandler()
        {
            Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, perHour: 200, perDay: 1500, perWeek: 3000)
            {
                IpThrottling = true
            },
            Repository = new MemoryCacheRepository()
        });

        appBuilder.UseWebApi(config);
    }
}

Endpoint throttling based on IP

If, from the same IP, in the same second, you'll make two calls to api/values, the last call will get blocked. But if in the same second you call api/values/1 too, the request will go through because it's a different route.

config.MessageHandlers.Add(new ThrottlingHandler()
{
	Policy = new ThrottlePolicy(perSecond: 1, perMinute: 30)
	{
		IpThrottling = true,
		EndpointThrottling = true
	},
	Repository = new CacheRepository()
});

Endpoint throttling based on IP and Client Key

If a client (identified by an unique API key) from the same IP, in the same second, makes two calls to api/values, then the last call will get blocked. If you want to apply limits to clients regardless of their IPs then you should set IpThrottling to false.

config.MessageHandlers.Add(new ThrottlingHandler()
{
	Policy = new ThrottlePolicy(perSecond: 1, perMinute: 30)
	{
		IpThrottling = true,
		ClientThrottling = true,
		EndpointThrottling = true
	},
	Repository = new CacheRepository()
});

IP and/or Client Key White-listing

If requests are initiated from a white-listed IP or Client, then the throttling policy will not be applied and the requests will not get stored. The IP white-list supports IP v4 and v6 ranges like "192.168.0.0/24", "fe80::/10" and "192.168.0.0-192.168.0.255" for more information check jsakamoto/ipaddressrange.

config.MessageHandlers.Add(new ThrottlingHandler()
{
	Policy = new ThrottlePolicy(perSecond: 2, perMinute: 60)
	{
		IpThrottling = true,
		IpWhitelist = new List<string> { "::1", "192.168.0.0/24" },
		
		ClientThrottling = true,
		ClientWhitelist = new List<string> { "admin-key" }
	},
	Repository = new CacheRepository()
});

IP and/or Client Key custom rate limits

You can define custom limits for known IPs or Client Keys, these limits will override the default ones. Be aware that a custom limit will only work if you have defined a global counterpart.

config.MessageHandlers.Add(new ThrottlingHandler()
{
	Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, perHour: 200, perDay: 1500)
	{
		IpThrottling = true,
		IpRules = new Dictionary<string, RateLimits>
		{ 
			{ "192.168.1.1", new RateLimits { PerSecond = 2 } },
			{ "192.168.2.0/24", new RateLimits { PerMinute = 30, PerHour = 30*60, PerDay = 30*60*24 } }
		},
		
		ClientThrottling = true,
		ClientRules = new Dictionary<string, RateLimits>
		{ 
			{ "api-client-key-1", new RateLimits { PerMinute = 40, PerHour = 400 } },
			{ "api-client-key-9", new RateLimits { PerDay = 2000 } }
		}
	},
	Repository = new CacheRepository()
});

Endpoint custom rate limits

You can also define custom limits for certain routes, these limits will override the default ones. You can define endpoint rules by providing relative routes like api/entry/1 or just a URL segment like /entry/. The endpoint throttling engine will search for the expression you've provided in the absolute URI, if the expression is contained in the request route then the rule will be applied. If two or more rules match the same URI then the lower limit will be applied.

config.MessageHandlers.Add(new ThrottlingHandler()
{
	Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, perHour: 200)
	{
		IpThrottling = true,
		ClientThrottling = true,
		EndpointThrottling = true,
		EndpointRules = new Dictionary<string, RateLimits>
		{ 
			{ "api/search", new RateLimits { PerSecond = 10, PerMinute = 100, PerHour = 1000 } }
		}
	},
	Repository = new CacheRepository()
});

Stack rejected requests

By default, rejected calls are not added to the throttle counter. If a client makes 3 requests per second and you've set a limit of one call per second, the minute, hour and day counters will only record the first call, the one that wasn't blocked. If you want rejected requests to count towards the other limits, you'll have to set StackBlockedRequests to true.

config.MessageHandlers.Add(new ThrottlingHandler()
{
	Policy = new ThrottlePolicy(perSecond: 1, perMinute: 30)
	{
		IpThrottling = true,
		ClientThrottling = true,
		EndpointThrottling = true,
		StackBlockedRequests = true
	},
	Repository = new CacheRepository()
});

Define rate limits in web.config or app.config

WebApiThrottle comes with a custom configuration section that lets you define the throttle policy as xml.

config.MessageHandlers.Add(new ThrottlingHandler()
{
    Policy = ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
    Repository = new CacheRepository()
});

Config example (policyType values are 1 - IP, 2 - ClientKey, 3 - Endpoint):

<configuration>
  
  <configSections>
    <section name="throttlePolicy" 
             type="WebApiThrottle.ThrottlePolicyConfiguration, WebApiThrottle" />
  </configSections>
  
  <throttlePolicy limitPerSecond="1"
                  limitPerMinute="10"
                  limitPerHour="30"
                  limitPerDay="300"
                  limitPerWeek ="1500"
                  ipThrottling="true"
                  clientThrottling="true"
                  endpointThrottling="true">
    <rules>
      <!--Ip rules-->
      <add policyType="1" entry="::1/10"
           limitPerSecond="2"
           limitPerMinute="15"/>
      <add policyType="1" entry="192.168.2.1"
           limitPerMinute="12" />
      <!--Client rules-->
      <add policyType="2" entry="api-client-key-1"
           limitPerHour="60" />
      <!--Endpoint rules-->
      <add policyType="3" entry="api/values"
           limitPerDay="120" />
    </rules>
    <whitelists>
      <!--Ip whitelist-->
      <add policyType="1" entry="127.0.0.1" />
      <add policyType="1" entry="192.168.0.0/24" />
      <!--Client whitelist-->
      <add policyType="2" entry="api-admin-key" />
    </whitelists>
  </throttlePolicy>

</configuration>

Retrieving API Client Key

By default, the ThrottlingHandler retrieves the client API key from the "Authorization-Token" request header value. If your API key is stored differently, you can override the ThrottlingHandler.SetIdentity function and specify your own retrieval method.

public class CustomThrottlingHandler : ThrottlingHandler
{
	protected override RequestIdentity SetIdentity(HttpRequestMessage request)
	{
		return new RequestIdentity()
		{
			ClientKey = request.Headers.Contains("Authorization-Key") ? request.Headers.GetValues("Authorization-Key").First() : "anon",
			ClientIp = base.GetClientIp(request).ToString(),
			Endpoint = request.RequestUri.AbsolutePath.ToLowerInvariant()
		};
	}
}

Storing throttle metrics

WebApiThrottle stores all request data in-memory using ASP.NET Cache when hosted in IIS or Runtime MemoryCache when self-hosted with Owin. If you want to change the storage to Velocity, Redis or a NoSQL database, all you have to do is create your own repository by implementing the IThrottleRepository interface.

public interface IThrottleRepository
{
	bool Any(string id);
	
	ThrottleCounter? FirstOrDefault(string id);
	
	void Save(string id, ThrottleCounter throttleCounter, TimeSpan expirationTime);
	
	void Remove(string id);
	
	void Clear();
}

Since version 1.2 there is an interface for storing and retrieving the policy object as well. The IPolicyRepository is used to update the policy object at runtime.

public interface IPolicyRepository
{
    ThrottlePolicy FirstOrDefault(string id);
    
    void Remove(string id);
    
    void Save(string id, ThrottlePolicy policy);
}

Update rate limits at runtime

In order to update the policy object at runtime you'll need to use the new ThrottlingHandler constructor along with ThrottleManager.UpdatePolicy function introduced in WebApiThrottle v1.2.

Register the ThrottlingHandler providing PolicyCacheRepository in the constructor, if you are self-hosting the service with Owin then use PolicyMemoryCacheRepository:

public static void Register(HttpConfiguration config)
{
    //trace provider
    var traceWriter = new SystemDiagnosticsTraceWriter()
    {
        IsVerbose = true
    };
    config.Services.Replace(typeof(ITraceWriter), traceWriter);
    config.EnableSystemDiagnosticsTracing();

    //Web API throttling handler
    config.MessageHandlers.Add(new ThrottlingHandler(
        policy: new ThrottlePolicy(perMinute: 20, perHour: 30, perDay: 35, perWeek: 3000)
        {
            //scope to IPs
            IpThrottling = true,
            
            //scope to clients
            ClientThrottling = true,
            ClientRules = new Dictionary<string, RateLimits>
            { 
                { "api-client-key-1", new RateLimits { PerMinute = 60, PerHour = 600 } },
                { "api-client-key-2", new RateLimits { PerDay = 5000 } }
            },

            //scope to endpoints
            EndpointThrottling = true
        },
        
        //replace with PolicyMemoryCacheRepository for Owin self-host
        policyRepository: new PolicyCacheRepository(),
        
        //replace with MemoryCacheRepository for Owin self-host
        repository: new CacheRepository(),
        
        logger: new TracingThrottleLogger(traceWriter)));
}

When you want to update the policy object call the static method ThrottleManager.UpdatePolicy anywhere in you code.

public void UpdateRateLimits()
{
    //init policy repo
    var policyRepository = new PolicyCacheRepository();

    //get policy object from cache
    var policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey());

    //update client rate limits
    policy.ClientRules["api-client-key-1"] =
        new RateLimits { PerMinute = 80, PerHour = 800 };

    //add new client rate limits
    policy.ClientRules.Add("api-client-key-3",
        new RateLimits { PerMinute = 60, PerHour = 600 });

    //apply policy updates
    ThrottleManager.UpdatePolicy(policy, policyRepository);

}

Logging throttled requests

If you want to log throttled requests you'll have to implement IThrottleLogger interface and provide it to the ThrottlingHandler.

public interface IThrottleLogger
{
	void Log(ThrottleLogEntry entry);
}

Logging implementation example with ITraceWriter

public class TracingThrottleLogger : IThrottleLogger
{
    private readonly ITraceWriter traceWriter;
        
    public TracingThrottleLogger(ITraceWriter traceWriter)
    {
        this.traceWriter = traceWriter;
    }
       
    public void Log(ThrottleLogEntry entry)
    {
        if (null != traceWriter)
        {
            traceWriter.Info(entry.Request, "WebApiThrottle",
                "{0} Request {1} from {2} has been throttled (blocked), quota {3}/{4} exceeded by {5}",
                entry.LogDate, entry.RequestId, entry.ClientIp, entry.RateLimit, entry.RateLimitPeriod, entry.TotalRequests);
        }
    }
}

Logging usage example with SystemDiagnosticsTraceWriter and ThrottlingHandler

var traceWriter = new SystemDiagnosticsTraceWriter()
{
    IsVerbose = true
};
config.Services.Replace(typeof(ITraceWriter), traceWriter);
config.EnableSystemDiagnosticsTracing();
            
config.MessageHandlers.Add(new ThrottlingHandler()
{
	Policy = new ThrottlePolicy(perSecond: 1, perMinute: 30)
	{
		IpThrottling = true,
		ClientThrottling = true,
		EndpointThrottling = true
	},
	Repository = new CacheRepository(),
	Logger = new TracingThrottleLogger(traceWriter)
});

Attribute-based rate limiting with ThrottlingFilter and EnableThrottlingAttribute

As an alternative to the ThrottlingHandler, ThrottlingFilter does the same thing but allows custom rate limits to be specified by decorating Web API controllers and actions with EnableThrottlingAttribute. Be aware that when a request is processed, the ThrottlingHandler executes before the http controller dispatcher in the Web API request pipeline, therefore it is preferable that you always use the handler instead of the filter when you don't need the features that the ThrottlingFilter provides.

Setup the filter as you would the ThrottlingHandler:

config.Filters.Add(new ThrottlingFilter()
{
    Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, 
    perHour: 200, perDay: 2000, perWeek: 10000)
    {
        //scope to IPs
        IpThrottling = true,
        IpRules = new Dictionary<string, RateLimits>
        { 
            { "::1/10", new RateLimits { PerSecond = 2 } },
            { "192.168.2.1", new RateLimits { PerMinute = 30, PerHour = 30*60, PerDay = 30*60*24 } }
        },
        //white list the "::1" IP to disable throttling on localhost
        IpWhitelist = new List<string> { "127.0.0.1", "192.168.0.0/24" },

        //scope to clients (if IP throttling is applied then the scope becomes a combination of IP and client key)
        ClientThrottling = true,
        ClientRules = new Dictionary<string, RateLimits>
        { 
            { "api-client-key-demo", new RateLimits { PerDay = 5000 } }
        },
        //white list API keys that don’t require throttling
        ClientWhitelist = new List<string> { "admin-key" },

        //Endpoint rate limits will be loaded from EnableThrottling attribute
        EndpointThrottling = true
    }
});

Use the attributes to toggle throttling and set rate limits:

[EnableThrottling(PerSecond = 2)]
public class ValuesController : ApiController
{
    [EnableThrottling(PerSecond = 1, PerMinute = 30, PerHour = 100)]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    [DisableThrotting]
    public string Get(int id)
    {
        return "value";
    }
}

Rate limiting with ThrottlingMiddleware

ThrottlingMiddleware is an OWIN middleware component that works the same as the ThrottlingHandler. With the ThrottlingMiddleware you can target endpoints outside of the WebAPI area, like OAuth middleware or SignalR endpoints.

Self-hosted configuration example:

public class Startup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        ...

        //throtting middleware with policy loaded from app.config
        appBuilder.Use(typeof(ThrottlingMiddleware),
            ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
            new PolicyMemoryCacheRepository(),
            new MemoryCacheRepository(),
            null,
            null);

        ...
    }
}

IIS hosted configuration example:

public class Startup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        ...

	//throtting middleware with policy loaded from web.config
	appBuilder.Use(typeof(ThrottlingMiddleware),
	    ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
	    new PolicyCacheRepository(),
	    new CacheRepository(),
        null,
        null);

        ...
    }
}

Custom ip address parsing

If you need to extract client ip's from e.g. additional headers then you can plug in custom ipAddressParsers. There is an example implementation in the WebApiThrottle.Demo project - WebApiThrottle.Demo.Net.CustomIpAddressParser

config.MessageHandlers.Add(new ThrottlingHandler(
    policy: new ThrottlePolicy(perMinute: 20, perHour: 30, perDay: 35, perWeek: 3000)
    {        
        IpThrottling = true,
        ///...
    },
    policyRepository: new PolicyCacheRepository(),
    repository: new CacheRepository(),
    logger: new TracingThrottleLogger(traceWriter),
    ipAddressParser: new CustomIpAddressParser()));

Custom Quota Exceeded Response

If you want to customize the quota exceeded response you can set the properties QuotaExceededResponseCode and QuotaExceededMessage.

config.MessageHandlers.Add(new ThrottlingHandler(
    policy: new ThrottlePolicy(perMinute: 20, perHour: 30, perDay: 35, perWeek: 3000)
    {        
        IpThrottling = true,
        ///...
    },
    repository: new CacheRepository(),
    QuotaExceededResponseCode = HttpStatusCode.ServiceUnavailable,
    QuotaExceededMessage = "Too many calls! We can only allow {0} per {1}"));

webapithrottle's People

Contributors

barakzan avatar brightsoul avatar cezarcretu avatar corruptcouch avatar craigkennedy avatar dmarlow avatar e-smith avatar independentvar avatar jasonkoneczny avatar jawn avatar jimmystridh avatar jrusbatch avatar martincostello avatar nickhillstc avatar omar avatar samschelfhout avatar stefanprodan avatar tanzy avatar yyjdelete avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webapithrottle's Issues

Should not prescribe request identity

There are so many ways to identify requests in systems, the architecture should not enforce its own header for this purpose, but rather provide an interface to let the consuming application decide how a request identity is defined (from a header, or any mechanism of their choosing, such as identifying anonymous users)

ThrottlePolicy default per-second.

Any reason why ThrottlePolicy's first argument, perSecond isn't an optional parameter like the rest of them? It's not a terrible inconvenience to use null when I only want rate limiting per-minute, but it looks a bit weird.

Change rules to type IDictionary<string, RateLimits>

The ThrottlePolicy class currently exposes three sets of rules: ClientRules, EndpointRules and IPRules, all of the of type Dictionary<string, RateLimit>. This means that I have to load all of the rules in memory in advance and that is not desirable for scalability.
What do you think of changing their type to IDictionary<string, RateLimit>, so the user could provide his own implementation of the dictionary? Rules could then be loaded when needed, from a remote key value store (for instance), and even change at runtime.

Question: Multiple Throttling-policies

Is it possible to have multiple throttling-policies at the same time?

For example I want to add a generic throttling to two policies:

1.) ClientThrottling which limits all requests independent of the route so that one user can only perform lets say 30 requests per second in total.

2.) ClientThrottling + EndpointThrottling: Limit the number of requests / second for each endpoint to 5 requests per second.

The goal is to allow the user to perform 'many' different requests at the same time while at the same time preventing him from spamming a single route.

As far as I see this is only possible by adding two ThrottlingHandlers at the same time.

As soon as you enable EndpointThrottling there won´t be any throttling when you 'spam' different routes, right?

Please let me know if this is the best approach to achieve what I want or if I am missing something. If there are no big drawbacks to the approach of using two ThrottlingHandlers at the same time, I will go for that approach.

How to to throttle regardless of IP address, Client Key or Endpoint?

hi,

Our requirement is to limit the number of API calls regardless of it has been originated from the same IP address or different. We also do not want to limit by Client API key or Endpoint. How can it be done.? I tried ThrottlePolicy with global perWeek = 1 and setting all(IpThrottling, EndPointThrottling,ClientThrottling) to false, but it did not help because I beleive Throttling is disabled.

Do you have any suggestion?

Question: would IThrottleRepository with async methods make sense?

I'm currently implementing the IThrottleRepository against Microsoft Azure Document DB. What's a bit of a shame is that the DocumentDB API is fully async whereas the IThrottleRepository is fully sync.

I was considering contributing to your project by adding async support for IThrottleRepository. However - does it make sense do you think? Of course, async await comes at a cost of building a state machine around the caller. So my question: do you think this could add to the library?

Loading client policies dynamically

I'm trying to figure out if there is a better way to load client policies w/o loading all of them on startup. I can load all via IThrottlePolicyProvider, but I think as the number of clients grows it would be bit on the heavy side.

So far I've tried creating a middleware to read api key from Authorization-Token header and do a lookup on it to find the client and their rate limits stored in a database. I then store client's rate limits in OWIN context so it can be accessed later on.

        public override async Task Invoke(IOwinContext context)
        {
            var headers = context.Request.Headers;

            if (headers != null && headers.Any(header => header.Key.Equals("Authorization-Token")))
            {
                var apiKey = headers
                    .FirstOrDefault(pair => pair.Key.Equals("Authorization-Token"))
                    .Value
                    .FirstOrDefault();

                var client = await _clientsRetriever.GetByApiKey(apiKey);

                if (client != null)
                {
                    context.Set("client.AuthorizationToken", apiKey);
                    context.Set("client.RateLimits", new RateLimits
                    {
                        PerWeek = client.RateLimits.RequestsPerWeek ?? 0,
                        PerDay = client.RateLimits.RequestsPerDay ?? 0,
                        PerMinute = client.RateLimits.RequestsPerMinute ?? 0,
                        PerHour = client.RateLimits.RequestsPerHour ?? 0,
                        PerSecond = client.RateLimits.RequestsPerSecond ?? 0
                    });
                }
            }

            await Next.Invoke(context);
        }

I then implemented IPolicyRepository.FirstOrDefault which appears to be getting called for all requests. Here, I'm basically returning ThrottlePolicy with the rate limits for the current client in OWIN context only.

        public ThrottlePolicy FirstOrDefault(string id)
        {
            var token = HttpContext.Current.GetOwinContext().Get<string>("client.AuthorizationToken");
            var rateLimit = HttpContext.Current.GetOwinContext().Get<RateLimits>("client.RateLimits");

            var throttlePolicy = new ThrottlePolicy(perSecond: 0, perMinute: 0, perHour: 0, perDay: 0, perWeek: 0)
            {
                ClientThrottling = true
            };

            if (rateLimit != null)
            {
                throttlePolicy.ClientRules.Add(token, rateLimit);
            }

            return throttlePolicy;
        }

I'm not showing all of the code, but in general this works ok. Howevert, a little cumbersome and I feel like I may be missing a feature in the library. Any suggestions?

Question : More fine grained throttling

Hi

I understand you can set your policy like so:

Policy = new ThrottlePolicy(perSecond: 1, perMinute: 20, perHour: 200, perDay: 1500, perWeek: 3000)

Is it possible to set a policy that allows one request every 5 seconds?

If I set perMinute: 12 , that seems to allow 12 in the first few seconds of a minute and then nothing afterwards

What I would like is to only allow one request, then the next allowed one is five seconds later

I assume fractional values for perSecond dont work

thanks

Create an OWIN middleware instead of a WebAPI-specific middleware

First of all, thanks for this project. It really does the job.
Have you considered creating a throttling OWIN middleware?
There might be other endpoints such as the OAuth bearer token middleware, which exposes a /token endpoint, or SignalR endpoints that could be protected under the same throttling middleware as WebAPI.

strong name signing

can you publish the nuget package with strong name signing?
We sign all our assemblies prior to release to our customers and we cant build our system without your assembly being signed

Feature Request: NET Core RC2/RTM support

Hi. I like your implementation here, but our project is built under dotNET Core RC2 at the moment so I was wondering whether you are able to create a dotNET Core supported version?

Allow handling Authentication

Hi Guys,

In my project I have HttpMessageHandler for my API Key authentication and I'm using the ThrottleHandler too.

This cenarius forces me to have have 2 handlers stacked, what I think can decrease the performance of the api.

So I have been thinking if we could implement a simple API Key authentication on the project.

What do you think guys?

Best regards,

Gabriel Marquez

Default Throttle Logging

Provide a default implementation of the IThrottleLogger that logs to Diagnostic Trace or provide a default implementation of the ITraceWriter. This will allow the throttle messages to dump straight to the logging pipeline that might already be in place.

Not working properly in work networks (diffrent users with same ip)

this module doesn't work properly in work networks and throttles all requests from different clients with same IP.
I mean this module doesn't care about sessions and looks at all users in workgroups with the same eye.
users don't need to login in my project so I didn't used Identity to have any client Key.
Is there any option to solve this problem ??

thanks
alireza

Pulling Client APIs

Can you provide a suggestion of best practise to pull client api's from a data store rather than the hard coded dictionary example? For example, (using MVC project) as a new user registers with the site an API is allocated to them (using an extension of the identity model) - subsequent api calls made by the user would then want to check the api key in the header against the list of api's (using EF/model)stored in SQL Server.

Hope that makes sense

many thanks

dependency on System.Web.Http 5.0.0.0

The documentation seems to suggest a depency on System.Web.Http 5.0.0.0 or greater. I have System.Web.Http version 5.2.2.0 and I'm blowing this exception:

Could not load file or assembly 'System.Web.Http, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

Azure Web Role Not Starting

Do you know of any issue while publishing Web Api Throttle on Azure? The role is restarting continuously.

Whitelist from configuration not working correctly

I think there is problem at 130-133 rows in ThrottlePolicy.cs

if (whitelists != null)
{
    policy.EndpointWhitelist.AddRange(whitelists.Select(x => x.Entry));
}

White list not working for IP and ClientKey, this probably should be something like this

policy.IpWhitelist = new List<string>();
policy.ClientWhitelist = new List<string>();


if (whitelists != null)
{
    policy.IpWhitelist.AddRange(whitelists.Where(x => x.PolicyType == ThrottlePolicyType.IpThrottling).Select(x => x.Entry));
    policy.ClientWhitelist.AddRange(whitelists.Where(x => x.PolicyType == ThrottlePolicyType.ClientThrottling).Select(x => x.Entry));
    policy.EndpointWhitelist.AddRange(whitelists.Where(x => x.PolicyType == ThrottlePolicyType.EndpointThrottling).Select(x => x.Entry));
}

how to using RequestIdentity and PolicyCacheRepository in the same time

Hi,

Before i use PolicyCacheRepository, the RequestIdentity works fine, but after i add "PolicyRepository = new PolicyCacheRepository()", Why my RequestIdentity never get called ?

This is my requirement, my API Key is not stored in the "Authorization-Token" request header, and i need to update my ClientRules at runtime
Thanks

FIPS Compliance

My environment required that encryption algorithms are FIPS compliant. The ThrottlingCore.ComputeThrottleKey method is using Sha1Managed which is not FIPS compliant. This article documents more on the issue.

For now I will create my own build, but I'd love to see a FIPS compliant switch for the throttling handler. Thanks for considering it.

ThrottlingMiddleware - Retrieving API Client Key

As stated in the documentation, to get the client API key from a custom header, one needs to override the ThrottlingHandler.SetIndentity function

However, if we use the ThrottlingMiddleware, how can this be done?

Rejected requests counter always being updated and saved.

Per the ReadMe:

By default, rejected calls are not added to the throttle counter.
...
If you want rejected requests to count towards the other limits, you'll have to set StackBlockedRequests to true.

Looking at the code, I can see that Repository.Save is called within ThrottlingCore.ProcessRequest, which is called from ThrottlingFilter roughly 10 lines before the overlimit check is performed.

Screenshot from Redis showing a counter of 13 (this was with a perMinute limit of 10):
overlimit_requests

I've tried this with setting StackBlockedRequests explicitly to false as well as leaving the default, both with the same result.

Add attribute based throttling

Hello,

In the MvcThrottle project attributes are used to enable / disable throttling on a controller or action. Is it possible to add this functionality to the WebApiThrottle project as well?

Kind regards,
Marco Zuiderwijk

Unit Testing

Hi,

I've been having a play with WebApiThrottle following your suggestion on SO.

No problems using it in Web API, however I'm having real problems from a unit testing perspective.

Basically all I'm trying to do is to set the "RemoteIpAddress" in OWIN as part of the unit test so the API will throttle (see line 88 of ThrottlingCore.cs).

I've tried a multitude of ways to try and set it and haven't go anywhere. The nearest I've got is the snippets below. It seems to setup correctly, but once we enter Web API land all the request properties get replaced.

I was wondering if you might be able to shed some light on how to unit test the throttling? I've added screenshots of the main parts of the code here:

Many thanks in advance,
Franz.

01-config
02-test-case
03-handler

ThrottlingMiddleware logging

I'm using the ThrottlingMiddleware in OWIN pipeline. I need to log requests rejected when quota is exceeded.

Since I have my own separate logging middleware preceding the ThrottlingMiddleware in the pipeline (so I can log all failed requests), the first issue for me was to figure out why IOwinContext.Response has HTTP Status of 200 after coming back from ThrottlingMiddleware while I obviously receive 429 in the client. I guess it's because you use IOwinResponse.OnSendingHeaders to populate the response and that happens when all the middlewares are done with processing (correct me if I'm wrong here).

So I decided to go with implementing a separate IThrottleLogger logger. The problem is that as I can see in the source of ThrottlingMiddleware (line 191 in tag 1.4.3), the ThrottleLogEntry is built with null as request value:

// log blocked request
if (Logger != null)
{
    Logger.Log(core.ComputeLogEntry(requestId, identity, throttleCounter, rateLimitPeriod.ToString(), rateLimit, null));
}

I understand that this is probably because you can't build an HttpRequestMessage in OWIN context, but this makes the logger pretty useless for me (I am more interested in the contents of the incoming request rather than client's key or IP).

Is there any way to solve this? Right now it seems to me that simply populating the IOwinContext.Response on the spot would fix my issue but maybe it violates some other assumption.

Thanks in advance.

IPAddress.Parse doesn't support Port numbers

We ran into an interesting use case where the port number came through with the IP address.

Message: [FormatException: An invalid IP address was specified.]
 System.Net.IPAddress.InternalParse(String ipString, Boolean tryParse):0
 WebApiThrottle.ThrottlingCore.ContainsIp(List`1 ipRules, String clientIp):7
 WebApiThrottle.ThrottlingCore.IsWhitelisted(RequestIdentity requestIdentity):8
 WebApiThrottle.ThrottlingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken):128
 System.Web.Http.HttpServer+<SendAsync>d__0.MoveNext():285

The IP address coming through had port numbers on the end of it. For example:

127.0.0.1:8080

This doesn't get parsed. You may want to do some cleanup on IpAddress strings before attempting to parse them.

P.S. This happened in an Azure environment.

If you think this is an issue that should be handled in this project I wouldn't mind submitting a PR.

Question: Using ThrottlingHandler & ThrottlingFilter together

Hi - Awesome Library!

We have had someone abusing our API, mainly creating tonnes of user accounts (13 thousand over a period of 3 hours or so).

Here is what I am trying to achieve:

  1. A global policy of 50 requests per second, per endpoint, per IP address
  2. A endpoint policy "POST: Users" that limits to 150 new users per hour

Basically - this means that while we are sleeping (say 10 hours) the attacker could only create a maximum of 1500 accounts. It also means that their could only be 150 "Real" user accounts per hour... We can manage that number over time but for now thats more than required.

At this stage this is what I have:

  1. A ThrottlingHandler with the global policy covering off number 1
  2. A ThrottlingFilter - I'm not 100% sure if I need this for the attribute filter but have it anyway.
  3. A [EnableThrottling] attribute on the "POST: Users" endpoint - which covers number 2.

My question:
Will the ThrottlingHandler & ThrottlingFilter work independent of each other? Or do they inherit each other's policies? And - does the above look ok?

Cheers,
Sam

ThrottlePolicy just reads IP type rules from config

ThrottlePolicy.cs doesn't convert all three types of rules into RateLimit objects, just the IP ones. Nor are the other ones initialized.

EndpointRules = new Dictionary<string, RateLimits>()
foreach (var item in rules.Where(r=> r.PolicyType == ThrottlePolicyType.IpThrottling))

Support .Net 4.0

Any chance you could add support for .Net 4.0? I've downloaded the project from Github and it was easy to migrate:

  • Install a new version of WebApi.Core: 4.0.30506
  • Change this line to use TaskCompletionSource instead of the more convenient Task.FromResult.

IP Address extraction should be configurable

We have a load balancer in front of our web apps and the ipaddress throttle is all based on the load balancer ip. We have Forwarded_For http header which contains the source ip address but there is no easy way I can see to configure the throttle to use this.

Feature request: reset user request count

We're using the library to prevent scrapers doing too many calls. The library works really well for this ( blocking true positives ) but of course, every now and then, also throttles a power-user ( false positive ).

So - my question is: would it be possible to expose methods return wheter or not a client IsThrottled and one that ResetRequestCounter ?

The class 'WebApiThrottle.ThrottlingMiddleware' does not have a constructor taking 5 arguments.

I am using the ThrottlingMiddleware and I get the following error

The class 'WebApiThrottle.ThrottlingMiddleware' does not have a constructor taking 5 arguments.

app.Use(typeof(ThrottlingMiddleware),
                new ThrottlePolicy(perSecond: 5, perMinute: 120, perHour: 700, perDay: 10000)
                {
                    IpThrottling = true,
                    ClientThrottling = true,
                    EndpointThrottling = true,
                },
                new PolicyCacheRepository(),
                new CacheRepository(),
                null);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.