Net8 根据IP,客户端限流(防ddos攻击),及记录SQL注入攻击日志

十年河东,十年河西,莫欺少年穷

学无止境,精益求精

最近不知道哪个SX,一直在尝试注入攻击我司服务器,其中上周五攻击了上万次,为了减少攻击次数,决定Net8写一款限流策略,于是周五加班搞定限流策略,但到了本周一,吊毛还是一直攻击,根据日志,都是SQL注入型攻击,除了系统各个API接口参数化或关键字过滤外,决定揪出幕后攻击人,那就写一块记录攻击人IP,请求参数,请求路径的日志中间件,必要时,可拨打110,通知网警逮捕违法人。

限流策略

限流策略的核心是根据不同客户端进行限流,也就是黑客发起ddos攻击时,触发限流策略后,黑客无法访问系统,但不影响其他客户正常使用,目前最常用的策略是根据请求人IP进行限流(注意:同一WiFi环境下,对外IP是相同的)

1、Net8项目中引入:

    <PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
    <PackageReference Include="AspNetCoreRateLimit.Redis" Version="2.0.0" />

2、在启动文件中注入限流相关服务

        #region 配置限流
        // 配置限流设置
        services.Configure<IpRateLimitOptions>(options =>
        {
            // 通用规则
            options.GeneralRules = new List<RateLimitRule>
{
    // 1分钟100次
    new RateLimitRule
    {
        Endpoint = "*",  // 所有端点
        Period = "1m",
        Limit = 100
    },
    // 15分钟800次
    new RateLimitRule
    {
        Endpoint = "*",
        Period = "15m",
        Limit = 800
    },
    // 30分钟1200次
    new RateLimitRule
    {
        Endpoint = "*",
        Period = "30m",
        Limit = 1200
    }
};

            // 获取真实客户端IP(根据代理配置调整)
            options.ClientIdHeader = "X-Real-IP";  // 如果使用Nginx等反向代理
                                                   // options.RealIpHeader = "X-Real-IP";  // 新版使用这个
        });

        // 注册IP限流计数器存储
        services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
        services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
        // 如果要用Redis存储计数器,替换为:
        // builder.Services.AddRedisRateLimiting();

        // 注册限流处理器
        services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
        services.AddSingleton<IProcessingStrategy, AsyncKeyLockProcessingStrategy>();
        //配置限流
        #endregion

注意这段代码的顺序

 这里采用服务器内存作为计数器

3、注册限流(注意注册的顺序)

app.UseRouting();
app.UseIpRateLimiting();

这里应放在UseRouting()后面

最后就是发布测试,您可以写成1分钟限制5次进行测试,写一个测试接口,在电脑端请求五次后,电脑端再次请求就会报最多请求五次的消息,同时,立马在手机端进行测试,这时手机端是正常的,同理,手机端请求五次后,再次请求,也是会报最多请求五次的消息。

测试代码如下:

public class testController : BaseController
{
    private readonly IHttpContextAccessor _httpContextAccessor; public testController(IHttpContextAccessor httpContextAccessor)
    { 
        _httpContextAccessor = httpContextAccessor;
    }

    /// <summary>
    /// 测试限流
    /// </summary>
    /// <returns></returns>
    [HttpGet("Test")]
    [AllowAnonymous]
    public IActionResult Test()
    {
        var ip = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
        return Ok(ip + "时间:"+DateTime.Now.ToString("HHmmss"));
    }
}

这样就完成了限流策略

SQL注入日志中间件

 sql注入攻击日志记录的方案:检测攻击人GET请求的参数或者POST/PUT请求的请求体是否含有SQL注入攻击关键字,如果有相应关键字,则记录攻击者的IP,请求的参数/请求体等其他信息,记录下来的日志可作为证据,通知网警处理

1、中间价代码

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using SugarDbContext;
using SugarDbReadContext;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace swap.Middlewares
{
    public class LoggingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<LoggingMiddleware> _logger;

        public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            // 获取请求IP
            var ipAddress = context.Connection.RemoteIpAddress?.ToString();

            // 获取路由信息(控制器和方法)
            var endpoint = context.GetEndpoint();

            string controllerName = null;
            string actionName = null;
            object[] routeValues = null;

            if (endpoint != null)
            {
                // 获取路由信息
                var routePattern = endpoint.Metadata.GetMetadata<Microsoft.AspNetCore.Routing.RouteNameMetadata>();

                var routeData = context.GetRouteData();

                if (routeData != null)
                {
                    routeValues = routeData.Values.Values.ToArray();
                    routeData.Values.TryGetValue("controller", out var controller);
                    routeData.Values.TryGetValue("action", out var action);
                    controllerName = controller?.ToString();
                    actionName = action?.ToString();
                }
            }

            // 读取请求参数(Query 和 Body)
            var request = context.Request;
            var queryParams = request.QueryString.HasValue ? request.QueryString.Value : "";

            // 如果需要读取请求体参数(如 POST JSON),需要启用 Buffer
            string bodyAsText = "";
            if (request.Method == HttpMethods.Post || request.Method == HttpMethods.Put)
            {
                request.EnableBuffering();
                using (var reader = new StreamReader(request.Body, leaveOpen: true))
                {
                    bodyAsText = await reader.ReadToEndAsync();
                    request.Body.Position = 0;
                }
            }

            var sqlKeywords = new List<string>
    {
        "select", "insert", "update", "delete", "drop", "truncate","create","sleep","intersect","except",
        "declare", "exec", "execute", "union", " or ", "and", " --", ";", "'",  "/*", "*/", "@@", "@", "xp_"
    };
            var bodyTxt = bodyAsText.ToLower();
            //微信小程序 模版消息 模板ID 带有 -- 因此 这里排除模版消息
            if (!string.IsNullOrEmpty(bodyTxt) && sqlKeywords.Any(keyword => bodyTxt.Contains(keyword)) && !bodyTxt.Contains("tmplid"))
            {
                // 记录信息
                _logger.LogError("Request IP: {IpAddress}", ipAddress);
                _logger.LogError("Controller: {Controller}, Action: {Action}", controllerName, actionName);
                _logger.LogError("Query Params: {QueryParams}", queryParams);
                _logger.LogError("Body: {Body}", bodyAsText);
            }
            var queryTxt = queryParams.ToLower();
            if (!string.IsNullOrEmpty(bodyTxt) && sqlKeywords.Any(keyword => bodyTxt.Contains(keyword)) && !bodyTxt.Contains("tmplid"))
            {
                // 记录信息
                _logger.LogError("Request IP: {IpAddress}", ipAddress);
                _logger.LogError("Controller: {Controller}, Action: {Action}", controllerName, actionName);
                _logger.LogError("Query Params: {QueryParams}", queryParams);
                _logger.LogError("Body: {Body}", bodyAsText);

            }


            // 继续处理请求
            await _next(context);
        }
    }
}

2、引用中间件:

  app.UseResponseCaching();
  app.UseMiddleware<LoggingMiddleware>();
  app.UseMiddleware<JwtMiddlewares>();
  app.UseMiddleware<ExceptionMiddlewares>();
  if (env.IsDevelopment())
      app.UseSwag("V1");

  app.UseAuthentication();


  app.UseHttpsRedirection(); 
  app.UseRouting();
  app.UseIpRateLimiting();
  app.UseCors();

 最后,告诫攻击者,违法终究会付出代价

posted @ 2025-06-10 14:40  天才卧龙  阅读(59)  评论(0)    收藏  举报