Cara terbaik untuk menerapkan pembatasan permintaan di ASP.NET MVC?

212

Kami sedang bereksperimen dengan berbagai cara untuk membatasi tindakan pengguna dalam periode waktu tertentu :

  • Batasi posting pertanyaan / jawaban
  • Batasi pengeditan
  • Batasi pengambilan umpan

Untuk saat ini, kami menggunakan Cache untuk hanya menyisipkan catatan aktivitas pengguna - jika catatan itu ada jika / ketika pengguna melakukan aktivitas yang sama, kami menekan.

Menggunakan Cache secara otomatis memberi kita data basi membersihkan dan menggeser jendela aktivitas pengguna, tetapi bagaimana skala itu bisa menjadi masalah.

Apa sajakah cara lain untuk memastikan bahwa permintaan / tindakan pengguna dapat dibatasi secara efektif (penekanan pada stabilitas)?

Jarrod Dixon
sumber
Apakah Anda mencoba membatasi per pengguna atau per pertanyaan? Jika per pengguna, bisa menggunakan sesi, yang merupakan set yang lebih kecil.
Greg Ogle
1
Itu per pengguna, tapi kami tidak bisa menggunakan Sesi, karena itu membutuhkan cookie - kami membatasi berdasarkan alamat IP saat ini.
Jarrod Dixon
1
Saat ini, pertimbangkan paket nuget github.com/stefanprodan/MvcThrottle untuk halaman MVC dan github.com/stefanprodan/WebApiThrottle untuk permintaan api web
Andy

Jawaban:

240

Berikut adalah versi umum dari apa yang telah kami gunakan di Stack Overflow selama setahun terakhir:

/// <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;
        }
    }
}

Penggunaan sampel:

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

Cache ASP.NET berfungsi seperti jagoan di sini - dengan menggunakannya, Anda dapat membersihkan entri throttle secara otomatis. Dan dengan pertumbuhan lalu lintas kami, kami tidak melihat bahwa ini adalah masalah di server.

Jangan ragu untuk memberikan umpan balik tentang metode ini; ketika kami membuat Stack Overflow lebih baik, Anda mendapatkan perbaikan Ewok Anda lebih cepat :)

Jarrod Dixon
sumber
5
pertanyaan cepat - Anda menggunakan nilai c.HttpContext.Request.UserHostAddress sebagai bagian dari kunci. Apakah nilai itu mungkin kosong atau nol atau semuanya bernilai sama? (yaitu, jika Anda menggunakan load balancer dan itu adalah IP dari mesin itu .. bukan klien sebenarnya) Seperti, lakukan proxy atau load balancers (yaitu BIG IP F5) masukkan data yang sama di sana dan Anda perlu memeriksa untuk X-Diteruskan-Untuk juga atau sesuatu?
Pure.Krome
7
@ Pure.Krome - ya, bisa jadi. Ketika mengambil IP client, kita menggunakan fungsi pembantu yang memeriksa kedua REMOTE_ADDRdan HTTP_X_FORWARDED_FORvariabel server dan sanitizes tepat.
Jarrod Dixon
3
@ BrettRobi, saya cukup yakin mereka memiliki afinitas server berdasarkan alamat IP pengguna. Jadi mereka kemungkinan masih akan memukul server yang sama.
mmcdole
4
Bagi Anda yang peduli dan telah membaca sejauh ini di aliran komentar ... kami akhirnya membuat pengalihan kami sendiri yang menghapus kunci cache throttle sebelum mengarahkan. Dengan cara ini semua pengalihan melewati kode untuk menghapus kunci dan tidak ada yang memicu atribut Throttle.
SLoret
4
Jika Anda mencari versi API Web ini, periksa di sini: stackoverflow.com/questions/20817300/…
Papa Burgundy
68

Microsoft memiliki ekstensi baru untuk IIS 7 yang disebut Dynamic IP Restrictions Extension untuk IIS 7.0 - Beta.

"Pembatasan IP Dinamis untuk IIS 7.0 adalah modul yang memberikan perlindungan terhadap penolakan serangan layanan dan kekerasan pada server web dan situs web. Perlindungan tersebut disediakan dengan memblokir sementara alamat IP dari klien HTTP yang membuat jumlah permintaan bersamaan yang luar biasa tinggi atau yang membuat banyak permintaan dalam periode kecil. " http://learn.iis.net/page.aspx/548/using-dynamic-ip-restrictions/

Contoh:

Jika Anda menetapkan kriteria untuk diblokir setelah X requests in Y millisecondsatau X concurrent connections in Y millisecondsalamat IP akan diblokir Y millisecondsmaka permintaan akan diizinkan lagi.

Notandy
sumber
1
Apakah Anda tahu jika itu menyebabkan masalah dengan perayap seperti Googlebot?
Helephant
1
Sekarang dirilis dan dibundel dengan IIS pada versi 8 - iis.net/learn/get-started/whats-new-in-iis-8/…
Matthew Steeples
Saya ingin menggunakan ini, tetapi TIDAK memungkinkan Anda untuk melambat <location>. Setiap permintaan untuk aplikasi atau tidak sama sekali.
Kasey Speakman
Tampaknya tidak berguna jika server web Anda berada di belakang load balancer, karena semua lalu lintas tampaknya berasal dari alamat IP yang sama. Kecuali saya kehilangan sesuatu yang jelas ...
Dscoduc
11

Kami menggunakan teknik yang dipinjam dari URL ini http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx , bukan untuk pelambatan, tetapi untuk Denial Of Service (DOS) orang miskin. Ini juga berbasis cache, dan mungkin mirip dengan apa yang Anda lakukan. Apakah Anda mencekik untuk mencegah serangan DOS? Router tentu dapat digunakan untuk mengurangi DOS; apakah menurut Anda router dapat menangani pelambatan yang Anda butuhkan?

Rob Kraft
sumber
1
Itu sudah cukup banyak yang sudah kita lakukan - tapi ini berhasil :)
Jarrod Dixon