原地址: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
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<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()); } } }