1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-22 02:51:33 +01:00

rate limiting APIs

This commit is contained in:
Kyle Spearrin 2016-11-12 18:43:32 -05:00
parent ac62d54a7b
commit 17f8d0f677
4 changed files with 112 additions and 1 deletions

View File

@ -0,0 +1,39 @@
using AspNetCoreRateLimit;
using Bit.Api.Models.Response;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Threading.Tasks;
namespace Bit.Api.Middleware
{
public class CustomIpRateLimitMiddleware : IpRateLimitMiddleware
{
private readonly IpRateLimitOptions _options;
public CustomIpRateLimitMiddleware(
RequestDelegate next,
IOptions<IpRateLimitOptions> options,
IRateLimitCounterStore counterStore,
IIpPolicyStore policyStore,
ILogger<IpRateLimitMiddleware> logger,
IIpAddressParser ipParser = null
) : base(next, options, counterStore, policyStore, logger, ipParser)
{
_options = options.Value;
}
public override Task ReturnQuotaExceededResponse(HttpContext httpContext, RateLimitRule rule, string retryAfter)
{
var message = string.IsNullOrWhiteSpace(_options.QuotaExceededMessage) ?
$"Slow down! Too many requests. Try again in {rule.Period}." : _options.QuotaExceededMessage;
httpContext.Response.Headers["Retry-After"] = retryAfter;
httpContext.Response.StatusCode = _options.HttpStatusCode;
httpContext.Response.ContentType = "application/json";
var errorModel = new ErrorResponseModel { Message = message };
return httpContext.Response.WriteAsync(JsonConvert.SerializeObject(errorModel));
}
}
}

View File

@ -23,6 +23,8 @@ using System.Linq;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json.Serialization;
using AspNetCoreRateLimit;
using Bit.Api.Middleware;
namespace Bit.Api
{
@ -61,6 +63,8 @@ namespace Bit.Api
var globalSettings = new GlobalSettings();
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), globalSettings);
services.AddSingleton(s => globalSettings);
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimitOptions"));
services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));
// Repositories
services.AddSingleton<IUserRepository, Repos.UserRepository>();
@ -70,6 +74,13 @@ namespace Bit.Api
// Context
services.AddScoped<CurrentContext>();
// Caching
services.AddMemoryCache();
// Rate limiting
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
// Identity
services.AddTransient<ILookupNormalizer, LowerInvariantLookupNormalizer>();
services.AddJwtBearerIdentity(options =>
@ -176,6 +187,10 @@ namespace Bit.Api
globalSettings.Loggr.ApiKey);
}
// Rate limiting
app.UseMiddleware<CustomIpRateLimitMiddleware>();
// Insights
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();

View File

@ -18,8 +18,10 @@
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Binder": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"Loggr.Extensions.Logging": "1.0.0",
"Microsoft.ApplicationInsights.AspNetCore": "1.0.0"
"Microsoft.ApplicationInsights.AspNetCore": "1.0.0",
"AspNetCoreRateLimit": "1.0.2"
},
"tools": {

View File

@ -24,5 +24,60 @@
"gcmApiKey": "SECRET",
"gcmAppPackageName": "com.x8bit.bitwarden"
}
},
"IpRateLimitOptions": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIpHeader": "X-Forwarded-For",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"IpWhitelist": [],
"EndpointWhitelist": [],
"ClientWhitelist": [],
"GeneralRules": [
{
"Endpoint": "post:/auth/token",
"Period": "1m",
"Limit": 10
},
{
"Endpoint": "post:/auth/token/two-factor",
"Period": "1m",
"Limit": 5
},
{
"Endpoint": "post:/accounts/register",
"Period": "1m",
"Limit": 2
},
{
"Endpoint": "post:/account/password-hint",
"Period": "1m",
"Limit": 2
},
{
"Endpoint": "post:/account/email-token",
"Period": "1m",
"Limit": 2
},
{
"Endpoint": "post:/account/email",
"Period": "1m",
"Limit": 5
},
{
"Endpoint": "put:/account/email",
"Period": "1m",
"Limit": 5
},
{
"Endpoint": "get:/alive",
"Period": "1m",
"Limit": 5
}
]
},
"IpRateLimitPolicies": {
"IpRules": []
}
}