diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj index 9e0b33c553..5d199dd6f0 100644 --- a/src/Api/Api.csproj +++ b/src/Api/Api.csproj @@ -18,7 +18,6 @@ - diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 8424cc7734..4c7db6b0ae 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -49,6 +49,7 @@ + diff --git a/src/Api/Middleware/CustomIpRateLimitMiddleware.cs b/src/Core/Utilities/CustomIpRateLimitMiddleware.cs similarity index 98% rename from src/Api/Middleware/CustomIpRateLimitMiddleware.cs rename to src/Core/Utilities/CustomIpRateLimitMiddleware.cs index 244e3f3b5a..a2fb40b5e8 100644 --- a/src/Api/Middleware/CustomIpRateLimitMiddleware.cs +++ b/src/Core/Utilities/CustomIpRateLimitMiddleware.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json; using System.Threading.Tasks; -namespace Bit.Api.Middleware +namespace Bit.Core.Utilities { public class CustomIpRateLimitMiddleware : IpRateLimitMiddleware { diff --git a/src/Identity/Startup.cs b/src/Identity/Startup.cs index bb0cd83706..c51fda2fd6 100644 --- a/src/Identity/Startup.cs +++ b/src/Identity/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Configuration; using Bit.Core; using Bit.Core.Utilities; using Serilog.Events; +using AspNetCoreRateLimit; namespace Bit.Identity { @@ -30,6 +31,11 @@ namespace Bit.Identity // Settings var globalSettings = services.AddGlobalSettingsServices(Configuration); + if(!globalSettings.SelfHosted) + { + services.Configure(Configuration.GetSection("IpRateLimitOptions")); + services.Configure(Configuration.GetSection("IpRateLimitPolicies")); + } // Data Protection services.AddCustomDataProtectionServices(Environment, globalSettings); @@ -40,6 +46,16 @@ namespace Bit.Identity // Context services.AddScoped(); + // Caching + services.AddMemoryCache(); + + if(!globalSettings.SelfHosted) + { + // Rate limiting + services.AddSingleton(); + services.AddSingleton(); + } + // IdentityServer services.AddCustomIdentityServerServices(Environment, globalSettings); @@ -67,6 +83,11 @@ namespace Bit.Identity return e.Level > LogEventLevel.Error; } + if(context.Contains(typeof(IpRateLimitMiddleware).FullName) && e.Level == LogEventLevel.Information) + { + return true; + } + return e.Level >= LogEventLevel.Error; }) .AddConsole() @@ -75,6 +96,12 @@ namespace Bit.Identity // Default Middleware app.UseDefaultMiddleware(env); + if(!globalSettings.SelfHosted) + { + // Rate limiting + app.UseMiddleware(); + } + // Add IdentityServer to the request pipeline. app.UseIdentityServer(); } diff --git a/src/Identity/settings.json b/src/Identity/settings.json index a2f4b590b5..6a53608fd9 100644 --- a/src/Identity/settings.json +++ b/src/Identity/settings.json @@ -47,5 +47,35 @@ "publicKey": "SECRET", "privateKey": "SECRET" } + }, + "IpRateLimitOptions": { + "EnableEndpointRateLimiting": true, + "StackBlockedRequests": false, + "RealIpHeader": "CF-Connecting-IP", + "ClientIdHeader": "X-ClientId", + "HttpStatusCode": 429, + "IpWhitelist": [], + "EndpointWhitelist": [], + "ClientWhitelist": [], + "GeneralRules": [ + { + "Endpoint": "*", + "Period": "1m", + "Limit": 60 + }, + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + }, + { + "Endpoint": "post:/connect/token", + "Period": "1m", + "Limit": 10 + } + ] + }, + "IpRateLimitPolicies": { + "IpRules": [] } }