private static string BuildRequestKey( ThrottlingProperties propertiesSet, ThrottlingPeriod period, NancyContext context, params string[] requestKeys) { using (var ms = new MemoryStream()) using (var sw = new StreamWriter(ms, Encoding.UTF8)) { if (propertiesSet.HasFlag(ThrottlingProperties.RemoteIp)) { sw.Write(context.GetClientHost()); } if (propertiesSet.HasFlag(ThrottlingProperties.Method)) { sw.Write(context.Request.Method); } if (propertiesSet.HasFlag(ThrottlingProperties.Path)) { sw.Write(context.Request.Path); } sw.Write(period); if (requestKeys != null) { foreach (var key in requestKeys) { sw.Write(key); } } sw.Flush(); ms.Position = 0; using (var algorithm = new SHA1Managed()) { var hash = algorithm.ComputeHash(ms); return(Convert.ToBase64String(hash)); } } }
private static async Task LogRequest( NancyContext ctx, ILifetimeScope requestContainer, HttpStatusCode?statusCode = null) { var repository = requestContainer.Resolve <IAccessLogRepository>(); var logger = requestContainer.Resolve <ILogger>(); try { var processingTime = CalculateProcessingTime(ctx); var sensitiveInfoInPathRegex = ctx.GetRegexForSensitiveInfoInPath(); var actionStr = sensitiveInfoInPathRegex != null ? sensitiveInfoInPathRegex.Replace(ctx.Request.Path, SensitiveInfoReplacement) : ctx.Request.Path; var logEntry = new AccessLogEntry { Action = Truncate(actionStr, 255), Method = Truncate(ctx.Request.Method, 15), ClientIp = Truncate(ctx.GetClientHost(), 255), StatusCode = (int?)(statusCode ?? ctx.Response?.StatusCode), ProcessedAt = DateTime.UtcNow, UserAgent = Truncate(string.Join(", ", ctx.Request.Headers["User-Agent"]), 255), UserId = Truncate(ctx.CurrentUser?.Identity?.Name, 128), ProcessingTime = processingTime, Referer = Truncate(ctx.Request.Headers.Referrer, 255), AcceptLanguage = ctx.Request.Headers["Accept-Language"].Any() ? Truncate(string.Join("|", ctx.Request.Headers["Accept-Language"]), 255) : null, }; await repository.Insert(logEntry); } catch (Exception ex) { logger.Error(ex, "LogRequest error"); } }
private Response CheckThrottlingLimitHook( NancyContext context, ThrottlingProperties propertiesSet, ThrottlingPeriod period, int requestCountLimit, Func <NancyContext, bool> checkIf = null, Func <NancyContext, bool> skipIf = null, params string[] requestKeys) { if (checkIf != null && !checkIf(context)) { return(null); } if (skipIf != null && skipIf(context)) { return(null); } var key = BuildRequestKey(propertiesSet, period, context, requestKeys); var expirationTime = CalculateExpirationTime(period); var counterValue = IncrementCounter(key, expirationTime); if (IsLimitExceeded(requestCountLimit, counterValue)) { if (IsNeedToLog(requestCountLimit, counterValue)) { logger.Error($"Flood detected ({counterValue} in {period.ToString()} allowed {requestCountLimit})" + $" on path: {context?.Request?.Path}" + $" ip: {context?.GetClientHost()}"); } return(new Response { StatusCode = HttpStatusCode.TooManyRequests }); } return(null); }