WebApi용 SQL 주입 필터

6217 단어 C##.NET작업 노트
개발 도구: Visual Studio 2017 C# 버전: C#7.1
가장 효과적인 SQL 주입 방지 방법은 데이터베이스를 호출할 때 매개 변수화된 조회를 사용하는 것이다.하지만 오래된 웹에이피 프로젝트를 맡는다면 데이터베이스 접근층의 코드를 많이 바꾸지 않으려면 어떻게 해야 하는가.
나의 해결 방안은 필터를 추가하는 것이다.
먼저 필터 방법을 쓰고 코드를 올리다
using System;
using System.Collections.Generic;
using System.Web;

namespace Test
{
    /// 
    ///   SQL  
    /// 
    public class AntiSqlInject
    {
        public static AntiSqlInject Instance = new AntiSqlInject();

        /// 
        ///        
        /// 
        static AntiSqlInject()
        {
            SqlKeywordsArray.AddRange(SqlSeparatKeywords.Split('|'));
            SqlKeywordsArray.AddRange(Array.ConvertAll(SqlCommandKeywords.Split('|'), h => h + " "));
            SqlKeywordsArray.AddRange(Array.ConvertAll(SqlCommandKeywords.Split('|'), h => " " + h));
        }

        private const string SqlCommandKeywords = "and|exec|execute|insert|select|delete|update|count|chr|mid|master|" +
                                                  "char|declare|sitename|net user|xp_cmdshell|or|create|drop|table|from|grant|use|group_concat|column_name|" +
                                                  "information_schema.columns|table_schema|union|where|select|delete|update|orderhaving|having|by|count|*|truncate|like";

        private const string SqlSeparatKeywords = "'|;|--|\'|\"|/*|%|#";

        private static readonly List SqlKeywordsArray = new List();

        /// 
        ///     
        /// 
        ///   
        ///   
        public bool IsSafetySql(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return true;
            }
            input = HttpUtility.UrlDecode(input).ToLower();

            foreach (var sqlKeyword in SqlKeywordsArray)
            {
                if (input.IndexOf(sqlKeyword, StringComparison.Ordinal) >= 0)
                {
                    return false;
                }
            }
            return true;
        }

        /// 
        ///        
        /// 
        ///   
        ///   
        public string GetSafetySql(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }
            if (IsSafetySql(input)) { return input; }
            input = HttpUtility.UrlDecode(input).ToLower();

            foreach (var sqlKeyword in SqlKeywordsArray)
            {
                if (input.IndexOf(sqlKeyword, StringComparison.Ordinal) >= 0)
                {
                    input = input.Replace(sqlKeyword, string.Empty);
                }
            }
            return input;
        }
    }
}


그 다음은 필터, 코드부터
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace Test
{
    /// 
    ///     
    /// 
    /// 
    /// SQL     
    /// 
    public class AntiSqlInjectFilter : ActionFilterAttribute
    {
        /// 
        /// 
        /// 
        /// 
        public override void OnActionExecuting(HttpActionContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            var actionParameters = filterContext.ActionDescriptor.GetParameters();

            var actionArguments = filterContext.ActionArguments;

            foreach (var p in actionParameters)
            {
                var value = filterContext.ActionArguments[p.ParameterName];

                var pType = p.ParameterType;

                if (value == null)
                {
                    continue;
                }
				//          ,     
                if (!pType.IsClass) continue;

                if (value is string)
                {
                    // string    
                    filterContext.ActionArguments[p.ParameterName] = AntiSqlInject.Instance.GetSafetySql(value.ToString());
                }
                else
                {
                    //   class, class    ,string         
                    var properties = pType.GetProperties();
                    foreach (var pp in properties)
                    {
                        var temp = pp.GetValue(value);
                        if (temp == null)
                        {
                            continue;
                        }
                        pp.SetValue(value, temp is string ? AntiSqlInject.Instance.GetSafetySql(temp.ToString()) : temp);
                    }
                }
            }

        }
    }
}

필터를 추가하여 ActionFilterAttribute를 계승하고 OnactionExecuting 방법을 다시 쓰고 인삼을 가져오며 인삼의string 형식의 모든 데이터를 필터합니다.두 가지 상황, 하나는 매개 변수가string 유형이고, 다른 하나는 클래스의 속성이다.필터 끝났어.
필터는 두 가지 사용 방식이 있는데, 하나는 구체적인 방법에 첨가하는 것이다
		[HttpPut,Route("api/editSomething")]
		[AntiSqlInjectFilter]
		public async Task EditSomeThingAsync([FromBody]SomeThing model)
        {
            var response = await SomeThingBusiness.Editsync(model);
            return response;
        }

하나는 WebApiConfig에서 전역 구성입니다.cs 파일의 Register 메서드에 필터 추가
using System.Web.Http;

namespace Test
{
    /// 
    /// WebApi  
    /// 
    public static class WebApiConfig
    {
        /// 
        ///       
        /// 
        /// 
        public static void Register(HttpConfiguration config)
        {                      
            // Web API   
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
			//      SQL    
	        config.Filters.Add(new AntiSqlInjectFilter());
        }
    }
}


테스트가 유효하다.

좋은 웹페이지 즐겨찾기