首页 > 数据库 >net 7 中间件sql 注入的方法

net 7 中间件sql 注入的方法

时间:2023-04-21 16:22:47浏览次数:32  
标签:logger string 中间件 sqlMail sql cs net data public

百度一下都是 filter 防止sql 注入的,其实到MVC 的fileter 已经浪费了很多性能,我们在管道组装的时候,就可以拦截非法字符。在中间件收集参数是比较麻烦的事情,、

知识点储备需要理解中间件,以及怎么封装中间件,我们netcore 都是add 一个服务+app.use 一个中间件开发方式  2 如果收集post 请求的参数,这个和filer 不一样  需要流的方式收集。如果还有其他办法,大家一起讨论一下 QQ 53262607 

首先我定义了几个类,充当角色说明一下 

 ISQLFormat.cs 定义接口,用来处理核心注入逻辑

SQLFormat.cs  实现类,用来具体实现

FilterSQLString.cs    optoins  预设需要过滤的非法字符串和 特殊符号

SendMail.cs               optoins   邮件内容

sqlMail                 optoins   发送邮件的配置

 

AddSQLFromateExtensions.cs    IOC 注入的需要的类

SqlFilterRequestMiddlewareExtensions.cs  管道中间件封装

SQLFormatMiddleWare.cs  中间件处理过程

 

结构如下

 

 

ISQLFormat.cs


 public interface ISQLFormat
    {
        /// <summary>
        /// 获取post 和get 的 所有参数 收集参数存放字典
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        Dictionary<string, string> FromQueryString(HttpRequest request);
    
        /// <summary>
        /// 校验参数和预定义的非法字符串比较 输出哪些是非法字符
        /// </summary>
        /// <param name="dic"></param>
        /// <param name="sql"></param>
        /// <returns></returns>
        string Checksqlstring(Dictionary<string, string> dic, string sql);
      
        /// <summary>
        /// options  当遇到非法sql 发送预警邮件
        /// </summary>
        /// <param name="sendMail"></param>
        /// <param name="sqlMail"></param>
        /// <returns></returns>
        bool SendEmails(SendMail sendMail, sqlMail sqlMail);
       

    }

  SQLFormat.cs

    public class SQLFormat : ISQLFormat
    {
        private readonly ILogger<SQLFormat> _logger;

        public SQLFormat(ILogger<SQLFormat> logger)
        {
            _logger = logger;
        }

        public string Checksqlstring(Dictionary<string, string> dic, string sql)
        {
            string result = string.Empty;
            if (dic.Count() == 0) { return result; }
            if (!string.IsNullOrEmpty(sql))
            {
                string[] arry = sql.Split('|');
                foreach (var item in arry)
                {
                    var a = dic.Where(x => x.Value.IndexOf(item) >= 0).FirstOrDefault();
                    if (!string.IsNullOrEmpty(a.Value))
                    {
                        result += $"item:{item} 和配置文件{a.Value}中的关键词匹配上了sql注入";
                        break;
                    }
                }
            }
            return result;

        }

        public Dictionary<string, string> FromQueryString(HttpRequest request)
        {
            string date = string.Empty;
            {
                if (request.Method.ToLower().Equals("post"))
                {
                    try
                    {
                        request.EnableBuffering();//允许重复读取
                        var reader = new StreamReader(request.Body);
                        date = reader.ReadToEndAsync().Result;//异步
                        request.Body.Position = 0;//重置,后续才能正确读取
                    }
                    catch (Exception)
                    {
                        date = string.Empty;
                    }
                    _logger.LogInformation($"From方法收集到的body 里面信息:{date}");
                    return GetFrom(date);
                }
                else
                {
                    date = request.QueryString.Value;
                    return GetQuery(date); ;
                }
            }
        }
        /// <summary>
        /// 收集post 的参数
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private Dictionary<string, string> GetFrom(string data)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            if (string.IsNullOrEmpty(data))
            {
                _logger.LogInformation($"获取from 提交的data中间件:{data}");
                return dic;
            }
            JObject obj = (JObject)JsonConvert.DeserializeObject(data)!;
            foreach (JProperty item in obj.Properties())
            {
                dic.Add(item.Path, item.Value.ToString());
            }
            return dic;
        }
        /// <summary>
        /// 收集 query 的参数
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private Dictionary<string, string> GetQuery(string data)
        {
            var dic = new Dictionary<string, string>();
            if (data.Contains("&") || data.Contains("="))
            {
                var args = HttpUtility.ParseQueryString(data);
                if (args == null || args.Count <= 0) { return dic; }
                foreach (var key in args.AllKeys)
                {
                    if (key == null) { continue; }
                    if (dic.ContainsKey(key))
                    {
                        dic[key] = args[key]!;
                    }
                    else
                    {
                        dic.Add(key, args[key]!);
                    }
                }
            }
            return dic;
        }
        /// <summary>
        /// 发现非法字符 过滤 并发送邮件
        /// </summary>
        /// <param name="sendMail"></param>
        /// <param name="sqlMail"></param>
        /// <returns></returns>
        public bool SendEmails(SendMail sendMail, sqlMail sqlMail)
        {
            if (sendMail.strTo != "" && sendMail.strBody != "" && sendMail.strSubject != "")
            {
                MailMessage mailMsg = new MailMessage();//实例化对象
                mailMsg.From = new MailAddress(sqlMail.EmailNameForm!, sqlMail.EmailNameFormT);//源邮件地址和发件人
                mailMsg.To.Add(new MailAddress(sendMail.strTo!));//收件人地址
                mailMsg.Subject = sendMail.strSubject;//发送邮件的标题
                StringBuilder sb = new StringBuilder();
                sb.Append(sendMail.strBody);
                mailMsg.Body = sb.ToString();//发送邮件的内容
                                             //指定smtp服务地址(根据发件人邮箱指定对应SMTP服务器地址)
                SmtpClient client = new SmtpClient();//格式:smtp.126.com  smtp.164.com
                client.Host = sqlMail.EmailNameFormIP!;
                //要用587端口
                client.Port = 25;//端口
                                 //加密
                                 //  client.EnableSsl = true;
                                 //通过用户名和密码验证发件人身份
                client.Credentials = new NetworkCredential(sqlMail.EmailServerUser, sqlMail.EmailNameFormPWD); // 
                try
                {
                    client.Send(mailMsg);
                    return true;
                }
                catch (SmtpException ex)
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
    }

  

 

FilterSQLString.cs   
public class FilterSQLString
    {
        public string? sqlstring { get; set; }
        public string? sqlparme { get; set; }
    }


SendMail.cs  
   public class SendMail
    {
        /// <summary>
        /// 发件人
        /// </summary>
        public string ?strTo { get; set; }
        /// <summary>
        /// 内容
        /// </summary>
        public string ?strBody { get; set; }
        /// <summary>
        /// 标题
        /// </summary>
        public string ?strSubject { get; set; }
    }

sqlMail.cs

    public class sqlMail
    {
        /// <summary>
        /// 发送邮件的基础配置
        /// </summary>
        public string ?EmailNameForm { get; set; }
        public string ?EmailNameFormT { get; set; }
        public string ?EmailNameFormIP { get; set; }
        public string ?EmailNameFormPWD { get; set; }
        public string ?EmailServerUser { get; set; }
    }

 

AddSQLFromateExtensions.cs  封装类

 public static class AddSQLFromateExtensions
    {
        /// <summary>
        /// 传参的
        /// </summary>
        /// <param name="services"></param>
        /// <param name="action"></param>
        public static void AddSQLFroma(this IServiceCollection services, Action<FilterSQLString> action)
        {
          
            services.Configure(action);
            services.AddTransient<ISQLFormat, SQLFormat>();
        }
        /// <summary>
        /// 非传参的
        /// </summary>
        /// <param name="services"></param>
        public static void AddSQLFromaInvoke( this WebApplicationBuilder builder)
        {
            builder.Services.Configure<sqlMail>(builder.Configuration.GetSection("sqlMail"));
            builder.Services.Configure<FilterSQLString>(builder.Configuration.GetSection("FilterSQLString"));
            builder.Services.Configure<sqlMail>(builder.Configuration.GetSection("RedisDistributedCache"));
            builder.Services.AddTransient<ISQLFormat, SQLFormat>();
            builder.Services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
        }
    }

SqlFilterRequestMiddlewareExtensions.cs

  public static class SqlFilterRequestMiddlewareExtensions
    {
        public static IApplicationBuilder SqlFilterRequest(this IApplicationBuilder app)
        {
            return app.UseMiddleware<SQLFormatMiddleWare>();
        }
    }

SQLFormatMiddleWare.cs 请求处理的核心业务类

public class SQLFormatMiddleWare
    {

        private readonly RequestDelegate _next;
        private readonly FilterSQLString _SqlOptions;
        private readonly sqlMail _sqlMail;
        private readonly SendMail _sendmail;
        private readonly ILogger<SQLFormatMiddleWare> _logger;
        private readonly IHttpContextAccessor _httpContext;
        private readonly ISQLFormat _sQLFormat;

        public SQLFormatMiddleWare(RequestDelegate next,
           IOptionsMonitor<FilterSQLString> monitor,
           IOptionsMonitor<SendMail> sendmail,
           ILogger<SQLFormatMiddleWare> logger,
           IOptionsMonitor<sqlMail> sqlMail,
           ISQLFormat sQLFormat,
            IHttpContextAccessor httpContext)
        {
            _next = next;
            _SqlOptions = monitor.CurrentValue;
            _sqlMail = sqlMail.CurrentValue;
            _sendmail = sendmail.CurrentValue;
            _logger = logger;
            _httpContext = httpContext;
            _sQLFormat = sQLFormat;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            //  await _next(context);
            context.Request.EnableBuffering();//允许重复读取
            string Path = context.Request.Path.Value!;
            //   HttpRequest a = context.Request;
            var data = _sQLFormat.FromQueryString(context.Request);
        //  string blackip = _cacheClientDB.Get<string>("blackipcache");///这里调redis 临时写死IP黑名单
             string blackip = "180.66.66.21";//过滤的ip  这里可以用redis 替代 偷懒了 
            string ip = _httpContext.HttpContext!.Connection.RemoteIpAddress!.ToString();
            _logger.LogInformation($"ip:{ip} blackip:{blackip}");
            if (!string.IsNullOrEmpty(blackip) && blackip.Contains(ip))
            {
                context.Response.StatusCode = 403;
                return;
            }
            _logger.LogInformation($"data:{data.Count}");
            var result = _sQLFormat.Checksqlstring(data, _SqlOptions.sqlstring!);
            if (!string.IsNullOrEmpty(result))
            {
                _logger.LogInformation($"result:{result}");
                context.Response.StatusCode = 401;
                _sendmail.strSubject = result;
                bool b = _sQLFormat.SendEmails(_sendmail, _sqlMail);
                _logger.LogInformation($"b:{b} result:{result}");
                return;
            }
            else
            {
                await _next(context); //一下环节
            }

        }
    }

appsettings.json

 

测试如下

postman  post 2个参数

 调试中我们看到 2个post 参数我们都收集到了

注入的字符串 已经过滤出来  

 然后返回401 

 

 postman 也可以观察到 返回值是401  

 

 

标签:logger,string,中间件,sqlMail,sql,cs,net,data,public
From: https://www.cnblogs.com/jasontarry/p/17336153.html

相关文章

  • mysql generate 1000000 rows with random data
    CREATETABLE`data`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`datetime`timestampNULLDEFAULTCURRENT_TIMESTAMP,`channel`int(11)DEFAULTNULL,`value`floatDEFAULTNULL,......
  • 【汇智学堂】docker+springboot+mysql之二(springboot打包发送至Ubuntu dockermysql目
    IDEA:DockerfileContent:FROMjava:8VOLUME/tmpADDhellodocker-0.0.1-SNAPSHOT.jar/app.jarRUNsh-c'touch/app.jar'ENVJAVA_OPTS=""ENTRYPOINT["sh","-c","java$JAVA_OPTS-Djava.security.egd=file:/dev/.......
  • 【汇智学堂】docker+springboot+mysql之三(制作镜像并运行项目)
    Docker镜像仓库地址:https://hub.docker.com由于有墙,所以配置国内镜像,我们使用阿里云的镜像地址https://dev.aliyun.com/search…运行命令制作镜像:dockerbuild-t[容器名].注意:后面有个点,表示当前目录下//镜像名随意,注意最后有一个点发现没有mysql:查看所有发现msyql:5.......
  • SQL注入漏洞--DVWA
    怎么判断sql注入漏洞呢?后台执行的SQL语句为SELECTfirst_name,last_nameFROMusersWHEREuser_id='$id';($id:用户输入的内容)用户输入的数据为:1'and1=1#这时SQL语句发生变化,在原有查询完成后会判断1=1(这明显是对的),如果判断正确才会有输出[#作用是注释(移除)后续SQL语......
  • .NET实现解析字符串表达式
    一、引子·功能需求我们创建了一个School对象,其中包含了教师列表和学生列表。现在,我们需要计算教师平均年龄和学生平均年龄。//创建对象Schoolschool=newSchool(){Name="小菜学园",Teachers=newList<Teacher>(){newTeacher(){Name="波老......
  • CentOS网卡无法启动返回'Failed to start LSB:Bring up/down networking.'
    装了一台虚机,配置docker服务的时候发现忘了开CPU虚拟化,关机开启后再登录,发现网卡down了,重启网卡报错。1.journalctl-ex  #查看日志,发现返回错误'FailedtostartLSB:Bringup/downnetworking.';2.vi/var/long/messages  #再查看系统日志,发现有关于NetworkManager的信......
  • 基于Jsp和MySQL实现的云音乐平台
    访问【WRITE-BUG数字空间】_[内附完整源码和文档]一、系统使用说明1.1配置开发环境:EclipseJavaEEIDEforWebDevelopers4.3.2开发语言:Java1.8MVC框架:Spring4.3.3web服务器:Tomcat开发系统:OSX/LINUX数据库:MySQL1.2相关路径controller:CloudMusic/src/controllermodel:CloudMus......
  • 微软的ADO.NET帮助类SqlHelper.cs
    微软的ADO.NET帮助类,SqlHelper.cs 1//===============================================================================2//MicrosoftDataAccessApplicationBlockfor.NET3//http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp4//......
  • SQL——练习:上展BOM
    --练习:元件上展BOMIFEXISTS(SELECT*FROMtempdb.dbo.sysobjectsWHEREid=OBJECT_ID(N'tempdb.dbo.#temp_bom'))--是否存在该临时表DROPTABLE#temp_bom--存在则删除CREATETABLE#temp_bom--创建临时表(ROOT_ITEM_IDUNIQUEIDENTIFIER,......
  • hiveSQL mapreduce任务调优
    sethive.merge.mapredfiles=true;--在Map-Reduce的任务结束时合并小文件setmapred.max.split.size=30000000;--决定每个map处理的最大的文件大小,单位为B--setmapred.min.split.size=10000000;--公司集群默认值--setmapred.min.split.size.per.node=;......