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

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

浙公网安备 33010602011771号