【问题标题】:How do I implement rate limiting in an ASP.NET MVC site?如何在 ASP.NET MVC 站点中实现速率限制?
【发布时间】:2010-06-21 04:16:59
【问题描述】:

我正在构建一个 ASP.NET MVC 站点,我想在其中限制经过身份验证的用户可以使用该站点的某些功能的频率。

虽然我从根本上了解速率限制的工作原理,但我无法想象如何以编程方式实现它而不产生主要的代码异味。

您能否通过 C# 示例代码向我指出一个解决此类问题的简单而强大的解决方案

如果重要的话,所有这些功能目前都表示为只接受HTTP POST 的操作。我最终可能还想为HTTP GET 函数实现速率限制,因此我正在寻找一种适用于所有此类情况的解决方案。

【问题讨论】:

标签: c# asp.net asp.net-mvc limit rate-limiting


【解决方案1】:

如果您使用的是 IIS 7,您可以查看Dynamic IP Restrictions Extension。另一种可能性是将其实现为操作过滤器:

[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();
}

【讨论】:

  • 你将如何扩展它以使用 429 - Too Many Requests 根据 RFC 6586
  • @StuartBlacker 我假设您将编辑以下行:filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; 从冲突到 429 错误。
  • 这里的解决方案很好。我喜欢它。我要看看我是否可以做某事(某事)类似的事情。可能是 LRU 或滑动窗口超时。
  • filterContext.Result = new HttpStatusCodeResult(429, "too many requests");
【解决方案2】:

看看 Jarrod 关于他们如何在 SO 上执行此操作的答案。

StackOverflow MVC Throttling

一些示例代码以及其工作原理的说明。

【讨论】:

  • 我有一个疑问,如果DOS 攻击攻击了Web 服务器怎么办,那么这个代码级保护有什么用呢?我们不需要网络服务器或机器级别的解决方案吗?
  • @stom - 如果DOS 攻击正在攻击您的网络服务器,那么您已经输掉了相当多的战斗。即使 Web 服务器只是简单地丢弃数据包,攻击也会占用带宽和服务器资源来侦听、检查和丢弃数据包。速率限制更多是为了防止来自单个用户或机器人的滥用,不一定是对DOS 攻击的全面防御,尽管它可能会有所帮助,因为您没有像没有速率那样为每个请求执行数据库调用/函数节流到位。
【解决方案3】:

.Net 6

检查一下:

Nuget: https://www.nuget.org/packages/DotNetRateLimiter/

很简单:

[HttpGet("")]
[RateLimit(PeriodInSec = 60, Limit = 3)]
public IEnumerable<WeatherForecast> Get()
{
    ....
}

甚至你可以通过路由或查询参数来控制请求:

[HttpGet("by-query/{id}")]
[RateLimit(PeriodInSec = 60, Limit = 3, RouteParams = "id", QueryParams = "name,family")]
public IEnumerable<WeatherForecast> Get(int id, string name, [FromQuery] List<string> family)
{
    ....
}

【讨论】:

    猜你喜欢
    • 2022-08-22
    • 2020-10-04
    • 2011-02-22
    • 2018-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-12
    • 1970-01-01
    相关资源
    最近更新 更多