简单的限流过滤器

· 浏览次数 : 9

小编点评

以下为归纳总结后的内容: 首先创建一个名为RateLimitFilter的类,实现ActionFilterAttribute,用于实现全局的限流功能。 在OnActionExecuting方法中,获取客户端的IP地址,并检查其访问频率。如果IP地址在一定时间内访问次数超过设定的最大值,则返回相应的错误提示信息。 创建一个名为FilterConfig的类,用于注册全球过滤器,将自定义的RateLimitFilter添加到过滤器集合中。 在Global.asax文件中,注册全局过滤器,以在应用程序启动时加载并执行该过滤器。 通过以上步骤,你可以实现在API接口中防止恶意刷请求的功能。

正文

API接口都是提供给第三方服务/客户端调用,所有请求地址以及请求参数都是暴露给用户的。

每次请求一个HTTP请求,用户都可以通过F12,或者抓包工具看到请求的URL链接,然后copy出来。这样是非常不安全的,有人可能会恶意的刷我们的接口,那这时该怎么办呢?

增加一个全局过滤器 获取客户端的IP  限制固定时间内的访问次数即可

第一步:创建全局过滤器 RateLimitFilter

 public class RateLimitFilter : ActionFilterAttribute
    {
        private const int MaxRequests = 30; //1分钟访问最大频率
        private bool StartUp = true; //是否启用
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (StartUp)
            {
                base.OnActionExecuting(context);
                string clientId = GetIP();
                if (GetCache(clientId) == null)
                {
                    SetCacheRelativeTime(clientId, 1, 60);
                }
                else
                {
                    var cs = int.Parse(GetCache(clientId).ToString());
                    SetCacheRelativeTime(clientId, cs += 1, 60);
                }
                //var x = int.Parse(GetCache(clientId).ToString());
                if (int.Parse(GetCache(clientId).ToString()) > MaxRequests)
                {
                    //返回值规范不统一
                    context.Result = new ContentResult { Content = "<script type='text/javascript'>alert('" + clientId + "  访问过于频繁,请稍等片刻!');</script><h1 style='text-align: center; color: red;'>" + clientId + "  访问过于频繁,请稍等片刻!<h1>" };

                    //返回值规范统一   前端有错误提示
                    //context.Result = new JsonResult()
                    //{
                    //    Data = new { Result = false, status = false, suc = false, message = "" + clientId + "  访问过于频繁,请稍等片刻!" },
                    //    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                    //};
                }
            } 
        }


        /// <summary>
        /// 获取客户端IP地址
        /// </summary>
        /// <returns>若失败则返回回送地址</returns>
        public static string GetIP()
        {
            //如果客户端使用了代理服务器,则利用HTTP_X_FORWARDED_FOR找到客户端IP地址
            string userHostAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            if (!string.IsNullOrEmpty(userHostAddress))
            {
                userHostAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString().Split(',')[0].Trim();
            }
            //否则直接读取REMOTE_ADDR获取客户端IP地址
            if (string.IsNullOrEmpty(userHostAddress))
            {
                userHostAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
            }
            //前两者均失败,则利用Request.UserHostAddress属性获取IP地址,但此时无法确定该IP是客户端IP还是代理IP
            if (string.IsNullOrEmpty(userHostAddress))
            {
                userHostAddress = HttpContext.Current.Request.UserHostAddress;
            }
            //最后判断获取是否成功,并检查IP地址的格式(检查其格式非常重要)
            if (!string.IsNullOrEmpty(userHostAddress) && IsIP(userHostAddress))
            {
                return userHostAddress;
            }
            return "127.0.0.1";
        }

        /// <summary>
        /// 检查IP地址格式
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool IsIP(string ip)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
        }

        #region  设置相对过期时间Cache值(即:访问激活后不过期)
        /// <summary>        
        /// 设置相对过期时间Cache值(即:访问激活后不过期)
        /// </summary>        
        /// <param name="objectkey"></param>        
        /// <param name="objObject"></param>        
        /// <param name="timeSpan">超过多少时间不调用就失效,单位是秒</param>        

        public static void SetCacheRelativeTime(string objectkey, object objObject, int timeSpan)
        {
            System.Web.Caching.Cache objCache = HttpRuntime.Cache;
            objCache.Insert(objectkey, objObject, null, DateTime.MaxValue, TimeSpan.FromSeconds(timeSpan));
        }
        #endregion

        #region  获取当前应用程序指定CacheKey的Cache值
        /// <summary>
        /// 获取当前应用程序指定CacheKey的Cache值
        /// </summary>
        /// <param name="CacheKey"></param>
        /// <returns></returns>y
        public static object GetCache(string CacheKey)
        {
            try
            {
                System.Web.Caching.Cache objCache = HttpRuntime.Cache;
                Object value = objCache[CacheKey];
                if (value != null)
                {
                    return value;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception)
            {
                return null;
            }

        }
        #endregion
    }

 

第二步:FilterConfig类并注册你的全局过滤器

 public class FilterConfig
 {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new RateLimitFilter()); // 过滤器
        }
 }

第三步:Global.asax 文件中注册全局过滤器

protected void Application_Start()
{
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            UnityConfig.RegisterComponents();

            // 注册全局过滤器
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

}

 

与简单的限流过滤器相似的内容:

简单的限流过滤器

API接口都是提供给第三方服务/客户端调用,所有请求地址以及请求参数都是暴露给用户的。 每次请求一个HTTP请求,用户都可以通过F12,或者抓包工具看到请求的URL链接,然后copy出来。这样是非常不安全的,有人可能会恶意的刷我们的接口,那这时该怎么办呢? 增加一个全局过滤器 获取客户端的IP 限制

1.8 运用C编写ShellCode代码

在笔者前几篇文章中,我们使用汇编语言并通过自定位的方法实现了一个简单的`MessageBox`弹窗功能,但由于汇编语言过于繁琐在编写效率上不仅要考验开发者的底层功底,还需要写出更多的指令集,这对于普通人来说是非常困难的,当然除了通过汇编来实现`ShellCode`的编写以外,使用C同样可以实现编写,在多数情况下读者可以直接使用C开发,只有某些环境下对ShellCode条件有极为苛刻的长度限制时才会

1.8 运用C编写ShellCode代码

在笔者前几篇文章中,我们使用汇编语言并通过自定位的方法实现了一个简单的`MessageBox`弹窗功能,但由于汇编语言过于繁琐在编写效率上不仅要考验开发者的底层功底,还需要写出更多的指令集,这对于普通人来说是非常困难的,当然除了通过汇编来实现`ShellCode`的编写以外,使用C同样可以实现编写,在多数情况下读者可以直接使用C开发,只有某些环境下对ShellCode条件有极为苛刻的长度限制时才会

通过mat获取OOM时对象信息的方法与过程

通过mat获取OOM时对象信息的方法与过程 背景 如果谁的耐心不好, 就让他去看MAT里的objects信息. 有项目出现了OOM的情况 我在公司这边有一台内存比较高的Win10机器. 然后帮助同事进行了dump文件的分析. 为了备忘, 这里简单总结一下. 时间总结 公司网络限速. 总结为: 下载2

解密网络通信的关键技术(下):DNS、ARP、DHCP和NAT,你了解多少?

本文探讨了动态主机配置协议(DHCP)和网络地址转换(NAT)技术的工作原理和应用。DHCP通过简化IP地址配置过程实现了动态地址分配,而NAT则解决了IPv4地址紧缺问题。我们还介绍了DHCP中继代理和NAT中的网络地址与端口转换(NAPT)概念。然而,这些技术也存在一些限制,如无法主动建立连接和...

[转帖]Linux 内核 | 网络流量限速方案大 PK

https://maimai.cn/article/detail?fid=1674483493&efid=UXVPILU_JTlqLrYhTkDStA 网络流量限速是一个经久不衰的话题,Linux 内核中已经实现了若干种流量限速的方式。 最简单的方式是通过定期采集速率,在超过指定的速率后直接丢包,但

TiDB的简单介绍以及进行资源限制的方式与方法

TiDB的简单介绍以及进行资源限制的方式与方法 TiDB的简介 TiDB是一个分布式数据库, 简介为: TiDB 是一个开源的分布式关系型数据库,它兼具了分布式数据库的水平扩展性和传统关系型数据库的 ACID 事务特性。 TiDB 最初由 PingCAP 公司开发,并于 2015 年开源发布。创始人

.NET 高效灵活的API速率限制解决方案

前言 FireflySoft.RateLimit是基于.NET Core和.NET Standard构建,支持多种速率限制算法和策略,包括固定窗口、滑动窗口、漏桶、令牌桶等。通过简单的配置和集成,开发者可以快速地将其应用到现有的Web API、微服务或中间件中,实现对请求的精确控制。 同时,该库还支

通过滑动窗口实现接口调用的多种限制策略

前言 有个邮箱发送的限制发送次数需求,为了防止用户恶意请求发送邮件的接口,对用户的发送邮件次数进行限制,每个邮箱60s内只能接收一次邮件,每个小时只能接收五次邮件,24小时只能接收十次邮件,一共有三个条件的限制。 实现方案 单机方案 单机简单实现可以用Caffeine,在Caffeine里面Key为

在 NGINX 中根据用户真实 IP 进行限制

需求 需要根据用户的真实 IP 进行限制, 但是 NGINX 前边还有个 F5, 导致 deny 指令不生效. 阻止用户的真实 IP 不是 192.168.14.* 和 192.168.15.* 的访问请求. 实现 最简单的实现如下: :notebook: 前置条件: 需要 nginx 前边的 lo