我们正在尝试各种方法来限制用户在给定时间段内的操作:
目前,我们正在使用Cache来简单地插入用户活动的记录 - 如果用户执行相同活动时存在该记录,我们就会加油。
使用缓存自动为我们提供过时的数据清理和用户的滑动活动窗口,但它如何扩展可能是一个问题。
还有哪些其他方法可以确保可以有效地限制请求/用户操作(强调稳定性)?
这是我们过去一年在Stack Overflow上使用的通用版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| /// <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;
}
}
} |
样品用法:
1 2 3 4 5
| [Throttle(Name="TestThrottle", Message ="You must wait {n} seconds before accessing this url again.", Seconds = 5)]
public ActionResult TestThrottle()
{
return Content("TestThrottle executed");
} |
ASP.NET Cache就像一个冠军 - 通过使用它,您可以自动清理您的油门条目。随着我们不断增长的流量,我们没有看到这是服务器上的问题。
随意提供有关此方法的反馈;当我们使Stack Overflow更好时,你的Ewok修复速度更快:)
Microsoft为IIS 7提供了一个新的扩展,称为IIS 7.0的动态IP限制扩展 - Beta。
"The Dynamic IP Restrictions for IIS 7.0 is a module that provides protection against denial of service and brute force attacks on web server and web sites. Such protection is provided by temporarily blocking IP addresses of the HTTP clients who make unusually high number of concurrent requests or who make large number of requests over small period of time."
http://learn.iis.net/page.aspx/548/using-dynamic-ip-restrictions/
例:
如果在X requests in Y milliseconds或X concurrent connections in Y milliseconds之后将条件设置为阻止,则Y milliseconds将阻止IP地址,然后将再次允许请求。
我们使用从这个URL http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx借来的技术,不是为了限制,而是为了穷人的拒绝服务(D.O.S)。这也是基于缓存的,可能与您正在执行的操作类似。你是不是要限制D.O.S.攻击?路由器当然可以用来减少D.O.S;你认为路由器可以处理你需要的节流吗?