Как реализовать ограничение скорости на сайте ASP.NET MVC?

Я создаю сайт ASP.NET MVC, где хочу ограничить частоту использования аутентифицированными пользователями некоторых функций сайта.

Хотя я понимаю, как работает ограничение скорости, я не могу представить себе, как реализовать его программно, не создавая серьезного запаха кода.

Можете ли вы указать мне на простое, но эффективное решение этой проблемы с помощью примера кода C #?

Если это важно, все эти функции в настоящее время выражаются как Действия, которые принимают только HTTP POST. Возможно, со временем я захочу реализовать ограничение скорости и для HTTP GET функций, поэтому я ищу решение, которое работает во всех таких обстоятельствах.


person Maxim Zaslavsky    schedule 21.06.2010    source источник
comment
Вот еще одно полное руководство, как это сделать, которое позволяет более гибкие интервалы: shieldui.com/blogs/rate-limiting-in-asp-net-mvc   -  person Vladimir Georgiev    schedule 05.01.2016


Ответы (2)


Если вы используете IIS 7, вы можете взглянуть на Dynamic Расширение ограничений IP. Другая возможность - реализовать это как фильтр действий:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class RateLimitAttribute : ActionFilterAttribute
{
    public int Seconds { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Using the IP Address here as part of the key but you could modify
        // and use the username if you are going to limit only authenticated users
        // filterContext.HttpContext.User.Identity.Name
        var key = string.Format("{0}-{1}-{2}",
            filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
            filterContext.ActionDescriptor.ActionName,
            filterContext.HttpContext.Request.UserHostAddress
        );
        var allowExecute = false;

        if (HttpRuntime.Cache[key] == null)
        {
            HttpRuntime.Cache.Add(key,
                true,
                null,
                DateTime.Now.AddSeconds(Seconds),
                Cache.NoSlidingExpiration,
                CacheItemPriority.Low,
                null);
            allowExecute = true;
        }

        if (!allowExecute)
        {
            filterContext.Result = new ContentResult
            {
                Content = string.Format("You can call this every {0} seconds", Seconds)
            };
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
        }
    }
}

А затем украсьте действие, которое нужно ограничить:

[RateLimit(Seconds = 10)]
public ActionResult Index()
{
    return View();
}
person Darin Dimitrov    schedule 21.06.2010
comment
Как бы вы расширили это, чтобы использовать 429 - Too Many Requests в соответствии с RFC 6586 - person Stuart Blackler; 11.07.2014
comment
@StuartBlacker Я полагаю, вы отредактируете следующую строку: filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; из Conflict в ошибку 429. - person NicholasFolk; 20.02.2017
comment
Отличное решение здесь. Я люблю это. Я собираюсь посмотреть, смогу ли я сделать что-нибудь подобное. Может быть, что-то с LRU или тайм-аутом скользящего окна. - person Pangamma; 21.05.2018

Взгляните на ответ Джаррода о том, как они это делают на SO.

StackOverflow MVC Throttling

Некоторый пример кода, а также объяснение того, как это работает.

person Tommy    schedule 21.06.2010
comment
Я сомневаюсь, что если атака DOS поразит веб-сервер, то почему эта защита на уровне кода поможет? Разве нам не нужно решение на уровне веб-сервера или машины? - person Shaiju T; 08.12.2017
comment
@stom - Если DOS атакует ваши веб-серверы, вы уже проиграли приличную часть битвы. Даже если веб-сервер просто отбрасывает пакеты, атака ограничивает полосу пропускания и ресурсы сервера для прослушивания, проверки и отбрасывания пакета (ов). Ограничение скорости больше предназначено для предотвращения злоупотреблений со стороны одного пользователя или ботов, не обязательно для полной защиты от атак DOS, хотя оно может немного помочь в том, что вы не выполняете вызовы / функции БД для каждого запроса, как если бы вы делали это без регулирования скорости в место. - person Tommy; 08.12.2017