Najlepszy sposób na wdrożenie ograniczania żądań w ASP.NET MVC?

212

Eksperymentujemy z różnymi sposobami ograniczania działań użytkowników w danym okresie :

  • Ogranicz posty na pytania / odpowiedzi
  • Ogranicz edycje
  • Ogranicz pobieranie danych

Na razie używamy pamięci podręcznej, aby po prostu wstawić rekord aktywności użytkownika - jeśli ten rekord istnieje, jeśli / kiedy użytkownik wykona tę samą aktywność, dławimy.

Korzystanie z bufora automatycznie zapewnia nam przestarzałe czyszczenie danych i przesuwanie okien aktywności użytkowników, ale sposób skalowania może być problemem.

Jakie są inne sposoby zapewnienia skutecznego ograniczania żądań / działań użytkownika (nacisk na stabilność)?

Jarrod Dixon
źródło
Czy próbujesz ograniczyć liczbę użytkowników lub pytania? Jeśli na użytkownika, można użyć sesji, która byłaby mniejszym zestawem.
Greg Ogle,
1
Jest to na użytkownika, ale nie mogliśmy korzystać z Sesji, ponieważ wymaga to plików cookie - ograniczamy obecnie na podstawie adresu IP.
Jarrod Dixon
1
W dzisiejszych czasach rozważ pakiety nuget github.com/stefanprodan/MvcThrottle dla stron MVC i github.com/stefanprodan/WebApiThrottle dla żądań interfejsu API
Andy

Odpowiedzi:

240

Oto ogólna wersja tego, czego używaliśmy w przepełnieniu stosu przez ostatni rok:

/// <summary>
/// Decorates any MVC route that needs to have client requests limited by time.
/// </summary>
/// <remarks>
/// Uses the current System.Web.Caching.Cache to store each client request to the decorated route.
/// </remarks>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ThrottleAttribute : ActionFilterAttribute
{
    /// <summary>
    /// A unique name for this Throttle.
    /// </summary>
    /// <remarks>
    /// We'll be inserting a Cache record based on this name and client IP, e.g. "Name-192.168.0.1"
    /// </remarks>
    public string Name { get; set; }

    /// <summary>
    /// The number of seconds clients must wait before executing this decorated route again.
    /// </summary>
    public int Seconds { get; set; }

    /// <summary>
    /// A text message that will be sent to the client upon throttling.  You can include the token {n} to
    /// show this.Seconds in the message, e.g. "Wait {n} seconds before trying again".
    /// </summary>
    public string Message { get; set; }

    public override void OnActionExecuting(ActionExecutingContext c)
    {
        var key = string.Concat(Name, "-", c.HttpContext.Request.UserHostAddress);
        var allowExecute = false;

        if (HttpRuntime.Cache[key] == null)
        {
            HttpRuntime.Cache.Add(key,
                true, // is this the smallest data we can have?
                null, // no dependencies
                DateTime.Now.AddSeconds(Seconds), // absolute expiration
                Cache.NoSlidingExpiration,
                CacheItemPriority.Low,
                null); // no callback

            allowExecute = true;
        }

        if (!allowExecute)
        {
            if (String.IsNullOrEmpty(Message))
                Message = "You may only perform this action every {n} seconds.";

            c.Result = new ContentResult { Content = Message.Replace("{n}", Seconds.ToString()) };
            // see 409 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
            c.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
        }
    }
}

Przykładowe użycie:

[Throttle(Name="TestThrottle", Message = "You must wait {n} seconds before accessing this url again.", Seconds = 5)]
public ActionResult TestThrottle()
{
    return Content("TestThrottle executed");
}

Pamięć podręczna ASP.NET działa tutaj jak mistrz - dzięki niej uzyskujesz automatyczne czyszczenie wpisów przepustnicy. A wraz z rosnącym ruchem nie widzimy, że jest to problem na serwerze.

Przekaż opinię na temat tej metody; kiedy ulepszymy Przepełnienie stosu, jeszcze szybciej naprawisz Ewok :)

Jarrod Dixon
źródło
5
szybkie pytanie - używasz wartości c.HttpContext.Request.UserHostAddress jako części klucza. Czy ta wartość jest możliwa pusta, pusta, czy może ta sama wartość? (tj. jeśli używasz modułu równoważenia obciążenia i jest to adres IP tej maszyny .. nie rzeczywistych klientów) Na przykład, wykonaj proxy lub moduł równoważenia obciążenia (tj. BIG IP F5) umieść tam te same dane i musisz to sprawdzić dla X-Forwarded-For też czy coś?
Pure.Krome
7
@ Pure.Krome - tak, może być. Podczas pobierania adresu IP klienta, używamy funkcji pomocnika, że kontrole zarówno REMOTE_ADDRi HTTP_X_FORWARDED_FORzmienne serwera i dezynfekuje odpowiednio.
Jarrod Dixon
3
@BrettRobi, jestem prawie pewien, że mają powinowactwo do serwera na podstawie adresu IP użytkownika. Więc prawdopodobnie nadal będą trafiać na ten sam serwer.
mmcdole,
4
Dla tych, którzy dbają o to i przeczytali to w komentarzach ... skończyliśmy pisać własne przekierowania, które usuwają klucz pamięci podręcznej przepustnicy przed przekierowaniem. W ten sposób wszystkie przekierowania przechodzą przez kod, aby usunąć klucz i żadne z nich nie wyzwala atrybutu przepustnicy.
SLoret
4
Jeśli szukasz tej wersji interfejsu API sieci Web, sprawdź tutaj: stackoverflow.com/questions/20817300/...
Papa Burgundy
68

Microsoft ma nowe rozszerzenie dla IIS 7 o nazwie Dynamic IP Restrictions Extension dla IIS 7.0 - Beta.

„Ograniczenia dynamicznego IP dla IIS 7.0 to moduł, który zapewnia ochronę przed atakami typu„ odmowa usługi ”i„ brute force ”na serwer WWW i strony internetowe. Takie zabezpieczenie zapewnia tymczasowe blokowanie adresów IP klientów HTTP, którzy wysyłają niezwykle dużą liczbę jednoczesnych żądań lub którzy składają dużą liczbę wniosków w krótkim okresie czasu ”. http://learn.iis.net/page.aspx/548/using-dynamic-ip-restrictions/

Przykład:

Jeśli ustawisz kryteria blokowania później X requests in Y millisecondslub X concurrent connections in Y millisecondsadres IP zostanie zablokowany, Y millisecondsżądania będą ponownie akceptowane.

notandy
źródło
1
Czy wiesz, czy spowodowało to problemy z robotami indeksującymi, takimi jak Googlebot?
Helephant
1
Jest teraz wydany i dołączony do IIS od wersji 8 - iis.net/learn/get-started/whats-new-in-iis-8/…
Matthew Steeples
Chciałbym tego użyć, ale NIE pozwala ci to dusić <location>. To każda prośba o aplikację lub żadna.
Kasey Speakman,
Nie wydaje się to przydatne, jeśli twoje serwery WWW znajdują się za modułem równoważenia obciążenia, ponieważ cały ruch będzie wyglądał na ten sam adres IP. Chyba że brakuje mi czegoś oczywistego ...
Dscoduc 30.09.19
11

Używamy techniki zapożyczonej z tego adresu URL http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx , nie do ograniczania przepustowości, ale do Denial Of Service (DOS) biedaka. Jest to również oparte na pamięci podręcznej i może być podobne do tego, co robisz. Czy dławisz się, aby zapobiec atakom DOS? Routery z pewnością można wykorzystać do zmniejszenia DOS; myślisz, że router poradzi sobie z potrzebnym ograniczeniem przepustowości?

Rob Kraft
źródło
1
Właśnie to już robimy - ale działa świetnie :)
Jarrod Dixon