【转】适用于WebApi的SQL注入过滤器

原地址:https://www.cnblogs.com/yechangzhong-826217795/p/10450581.html

开发工具:Visual Studio 2017
C#版本:C#7.1

最有效的防止SQL注入的方式是调用数据库时使用参数化查询。
但是如果是接手一个旧的WebApi项目,不想改繁多的数据库访问层的代码,应该如何做。

我的解决方案是加一个过滤器。

先写过滤方法,上代码

复制代码
using System;
using System.Collections.Generic;
using System.Web;

namespace Test
{
    /// <summary>
    /// 防止SQL注入
    /// </summary>
    public class AntiSqlInject
    {
        public static AntiSqlInject Instance = new AntiSqlInject();

        /// <summary>
        /// 初始化过滤方法
        /// </summary>
        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<string> SqlKeywordsArray = new List<string>();

        /// <summary>
        /// 是否安全
        /// </summary>
        /// <param name="input">输入</param>
        /// <returns>返回</returns>
        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;
        }

        /// <summary>
        /// 返回安全字符串
        /// </summary>
        /// <param name="input">输入</param>
        /// <returns>返回</returns>
        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;
        }
    }
}
复制代码

然后是过滤器,先上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using  System.Web.Http.Controllers;
using  System.Web.Http.Filters;
 
namespace  Test
{
     /// <inheritdoc>
     ///     <cref></cref>
     /// </inheritdoc>
     /// <summary>
     /// SQL注入过滤器
     /// </summary>
     public  class  AntiSqlInjectFilter : ActionFilterAttribute
     {
         /// <inheritdoc />
         /// <summary>
         /// </summary>
         /// <param name="filterContext"></param>
         public  override  void  OnActionExecuting(HttpActionContext filterContext)
         {
             base .OnActionExecuting(filterContext);
             var  actionParameters = filterContext.ActionDescriptor.GetParameters();
 
             var  actionArguments = filterContext.ActionArguments;
 
             foreach  ( var  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<bool> EditSomeThingAsync([FromBody]SomeThingmodel)
        {
            var response = await SomeThingBusiness.Editsync(model);
            return response;
        }
复制代码

一种是全局配置,在WebApiConfig.cs文件中的Register方法中加上过滤器

复制代码
using System.Web.Http;

namespace Test
{
    /// <summary>
    /// WebApi配置
    /// </summary>
    public static class WebApiConfig
    {
        /// <summary>
        /// 注册配置服务
        /// </summary>
        /// <param name="config"></param>
        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());
        }
    }
}
复制代码

转载于:https://www.cnblogs.com/janeaiai/p/11236333.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值