问题背景:由于公司需要整改的老系统的漏洞检查,而系统就是没有使用参数化SQL即拼接查询语句开发的程序,导致漏洞扫描出现大量SQL注入问题。
解决方法:最好的办法就是不写拼接SQL,改用参数化SQL,推荐新项目使用,老项目改起来比较麻烦,花费的时间也多,最后选择用全局SQL过滤器过滤前端发送的请求内容。
代码:
/// <summary>
/// 防止输入参数sql注入:Post Get Cookies
/// </summary>
public class SqlFilter : ActionFilterAttribute
{
private const string FilterSql = "execute,exec,select,insert,update,delete,create,drop,alter,exists,table,sysobjects,truncate,union,and,order,xor,or,mid,cast,where,asc,desc,xp_cmdshell,join,declare,nvarchar,varchar,char,sp_oacreate,wscript.shell,xp_regwrite,',%,;,--";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// -----------------------防 Post 注入-----------------------
if (filterContext.HttpContext.Request.Form != null)
{
var isReadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
//把 Form 属性改为可读写
isReadonly?.SetValue(filterContext.HttpContext.Request.Form, false, null);
for (var k = 0; k < filterContext.HttpContext.Request.Form.Count; k++)
{
var inputKey = filterContext.HttpContext.Request.Form.Keys[k];
var inputValue = filterContext.HttpContext.Request.Form[inputKey];
var filters = FilterSql.Split(',');
inputValue = filters.Aggregate(inputValue, (current, filterSql) => Regex.Replace(current, filterSql, "", RegexOptions.IgnoreCase));
filterContext.HttpContext.Request.Form[inputKey] = inputValue;
}
}
// -----------------------防 GET 注入-----------------------
if (filterContext.HttpContext.Request.QueryString != null)
{
var isReadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
//把 QueryString 属性改为可读写
isReadonly?.SetValue(filterContext.HttpContext.Request.QueryString, false, null);
for (var k = 0; k < filterContext.HttpContext.Request.QueryString.Count; k++)
{
var inputKey = filterContext.HttpContext.Request.QueryString.Keys[k];
var inputValue = filterContext.HttpContext.Request.QueryString[inputKey];
var filters = FilterSql.Split(',');
inputValue = filters.Aggregate(inputValue, (current, filterSql) => Regex.Replace(current, filterSql, "", RegexOptions.IgnoreCase));
filterContext.HttpContext.Request.QueryString[inputKey] = inputValue;
}
}
// -----------------------防 Cookies 注入-----------------------
if (filterContext.HttpContext.Request.Cookies.Count > 0)
{
var isReadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
//把 Cookies 属性改为可读写
isReadonly?.SetValue(filterContext.HttpContext.Request.Cookies, false, null);
for (var k = 0; k < filterContext.HttpContext.Request.Cookies.Count; k++)
{
var inputKey = filterContext.HttpContext.Request.Cookies.Keys[k];
var inputValue = filterContext.HttpContext.Request.Cookies[inputKey]?.Value;
var filters = FilterSql.Split(',');
inputValue = filters.Aggregate(inputValue, (current, filterSql) => Regex.Replace(current, filterSql, "", RegexOptions.IgnoreCase));
if (!(filterContext.HttpContext.Request.Cookies[inputKey] is null))
{
filterContext.HttpContext.Request.Cookies[inputKey].Value = inputValue;
}
}
}
base.OnActionExecuting(filterContext);
}
}