MVC中利用ActionFilterAttribute过滤关键字

在开发过程中,有时候会对用户输入进行过滤,以便保证平台的安全性。屏蔽的方法有很多种,但是今天我说的这种主要是利用MVC中的ActionFilterAttribute属性来实现。由于MVC天然支持AOP,所以我们这种过滤方式正好利用了MVC的这种特性。

下面请看步骤:

首先,当用户输入自己的名称的时候,带有类似<BR>的内容的时候,由于MVC默认是需要验证内容的,所以,会抛出一张黄页错误,提示用户:从客户端检测到潜在风险的Request值。这种页面是极为不友好的,同时也是我们作为开发最不想见到的页面,屏蔽这个错误很简单,就是在响应的页面ActionResult上面加上[ValidateInput(false)]的特性,这样当用户提交的时候,页面将不会再次对输入内容做检测。

如果容忍这样的行为,将会对系统的安全性造成威胁,所以最好的解决方法就是讲其中类似 <>等进行转义。

下面我们就来利用ActionFilterAttribute构造自己的转义过滤类:

   1:  using System.Web.Mvc;
   2:  using TinyFrame.Plugin.StrongTyped.Models;
   3:   
   4:  namespace TinyFrame.Plugin.StrongTyped
   5:  {
   6:      public class FilterCharsAttribute : ActionFilterAttribute
   7:      {
   8:          protected string parameterName = "t";
   9:          protected TestModel model;
  10:   
  11:          public override void OnActionExecuting(ActionExecutingContext filterContext)
  12:          {
  13:              base.OnActionExecuting(filterContext);
  14:   
  15:              //No Parameters, will return directly.
  16:              if (!filterContext.ActionParameters.ContainsKey(parameterName))
  17:                  return;
  18:   
  19:              var t = filterContext.ActionParameters[parameterName] as TestModel;
  20:   
  21:              //No Entity data, will return directly
  22:              if (t == null)
  23:                  return;
  24:   
  25:              //Replace chars that should be filtered
  26:              if (!string.IsNullOrEmpty(t.TName))
  27:                  t.TName = t.TName.Replace("<", "&lt").Replace(">", "&gt");
  28:              if (!string.IsNullOrEmpty(t.TSite))
  29:                  t.TSite = t.TSite.Replace("<", "&lt").Replace(">", "&gt");
  30:          }
  31:      }
  32:  }

第8行,代表我们的用户输入的实体类参数,具体的Controller代码如下:

   1:    public ActionResult Index(TestModel t)
   2:          {
   3:              ViewData["ConvertedModel"] = t;
   4:              return View();
   5:          }

第11行,通过重载OnActionExecuting方法,我们可以定义自己的Filter。

第19行,将获取的Input结果转换成entity。

第27,29行,将潜在的危险字符进行转义。

这样书写完毕之后,我们就打造了一个可以过滤掉关键字的Filter了。如果想要做的通用的话,需要对输入的filterContext.ActionParameters进行遍历,并通过反射构建实例,再通过反射字段值,实现通用的关键字过滤。这里我只提供思路,具体的做法就看自己了。

然后将这个方法加入到Controller中需要检测的页面的头部,即可:

   1:  [ValidateInput(false)]
   2:  [FilterChars]
   3:  public ActionResult Index(TestModel t)
   4:  {
   5:       ViewData["ConvertedModel"] = t;
   6:       return View();
   7:  }

这样,我们就完成了对输入数据的过滤操作,下面看看结果吧:

QQ截图20140422211039

 

 

 

 

 

 

 

 

 

我们可以清楚的看到,输入结果,输出后,一对尖角号被转义了。

在开发程序的过程中,稍微不注意就会隐含有sql注入的危险。今天我就来说下,ASP.NET mvc 5使用Filter过滤Action参数防止sql注入,让你代码安全简洁。不用每下地方对参数的值都进行检查,看是用户输入的内容是否有危险的sql。如果没个地方都要加有几个缺点:

1、工作量大

2、容易遗漏

3、不容易维护

下面我通过写一个过滤防止sql的特性类,对Action执行前对Action的参数进行处理,如果有其值有sql语句,就会这些非法字符替换为空字符串。

一、sql注入的例子:

上面的输入有两个输入框,用户可以输入任何的值,包括有sql注入的值。

后台代码:

AdminController.cs

 
  1. public class AdminController : Controller
  2. {
  3. public ActionResult Index(string name = "", string loginName = "", int page = 1)
  4. {
  5. ViewBag.Name = name;
  6. ViewBag.LoginName = loginName;
  7. var r = DAdmin.GetList(name, loginName, page, 2);
  8. return View(r);
  9. }
  10. }
  11. }
DAdmin.cs:
 
  1. public class DAdmin
  2. {
  3. public static PageDataView<MSys_Admin> GetList(string name, string loginName, int page,int pageSize=10)
  4. {
  5. PageCriteria criteria = new PageCriteria();
  6. criteria.Condition = "1=1";
  7. if (!string.IsNullOrEmpty(name))
  8. criteria.Condition += string.Format(" and Name like '%{0}%'", name);
  9. if (!string.IsNullOrEmpty(loginName))
  10. criteria.Condition += string.Format(" and LoginName like '%{0}%'", loginName);
  11. criteria.CurrentPage = page;
  12. criteria.Fields = "*";
  13. criteria.PageSize = pageSize;
  14. criteria.TableName = "Sys_Admin a";
  15. criteria.PrimaryKey = "UID";
  16. var r = Common.GetPageData<MSys_Admin>(criteria);
  17. return r;
  18. }
  19. }

上面对用户输入的name和loginName两个参数没有判断是否有sql注入的非法字符,就直接拼接到sql语句,到数据库中执行,这样是非常危险的。

1、比如用户在name输入这样的内容:

%'--%

这样拼接出来的sql语句就成了

SELECT * FROM Sys_Admin WHERE Name like '%'--%'

这样“--”是sql的注释标记后面再拼接的sql语句都当成注释了,这样有效的就成了这样的sql语句:

SELECT * FROM Sys_Admin WHERE Name like '%'

这表示显示全部的记录。如果是登录的sql就会跳过用户名、密码的验证。


2、如果用户name输入内容带有insert或delete或者drop,比如:

namer人值为:%';DELETE FROM Sys_Admin--%

拼接成的sql成了:

SELECT * FROM Sys_Admin WHERE Name like '%';DELETE FROM Sys_Admin--%'

这样一执行就把Sys_Admin表的记录全部删除了。


总结:上面可以看到这种sql注入是多么的危险。

二、解决MVC sql注入方案

1、定义一个防止sql注入的字符串辅助类

 
  1. public class StringHelper
  2. {
  3. public static string FilterSql(string s)
  4. {
  5. if (string.IsNullOrEmpty(s)) return string.Empty;
  6. s = s.Trim().ToLower();
  7. s = ClearScript(s);
  8. s = s.Replace("=", "");
  9. s = s.Replace("'", "");
  10. s = s.Replace(";", "");
  11. s = s.Replace(" or ", "");
  12. s = s.Replace("select", "");
  13. s = s.Replace("update", "");
  14. s = s.Replace("insert", "");
  15. s = s.Replace("delete", "");
  16. s = s.Replace("declare", "");
  17. s = s.Replace("exec", "");
  18. s = s.Replace("drop", "");
  19. s = s.Replace("create", "");
  20. s = s.Replace("%", "");
  21. s = s.Replace("--", "");
  22. return s;
  23. }
  24. }
这个类对上面sql相关的字符串都替换掉。

2、定义一个用来检查并处理Action参数的特性类

 
  1. public class AntiSqlInjectAttribute:FilterAttribute,IActionFilter
  2. {
  3. public void OnActionExecuted(ActionExecutedContext filterContext)
  4. {
  5. }
  6. public void OnActionExecuting(ActionExecutingContext filterContext)
  7. {
  8. var actionParameters = filterContext.ActionDescriptor.GetParameters();
  9. foreach (var p in actionParameters)
  10. {
  11. if (p.ParameterType == typeof(string))
  12. {
  13. if (filterContext.ActionParameters[p.ParameterName] != null)
  14. {
  15. filterContext.ActionParameters[p.ParameterName] = StringHelper.FilterSql(filterContext.ActionParameters[p.ParameterName].ToString());
  16. }
  17. }
  18. }
  19. }
  20. }

说明:这个特性类是继承了类FilterAttribute和实现了接口IActionFilter,这里在方法OnActionExecuting处理Action的参数,OnActionExecuting是在Action执行之前运行的方法,而OnActionExecuted是在Action执行之后运行的方法。

p.ParameterType == typeof(string)

因为sql注入只有参数类型为字符串的时候才有可能所以这里只对Action参数为字符串的参数进行处理。


filterContext.ActionParameters[p.ParameterName] = 
StringHelper.FilterSql(filterContext.ActionParameters[p.ParameterName].ToString());
是用过滤之后的安全的Action参数值替换原来的原始值。

3、防止sql注入特性类的在MVC的Controller中的使用

 
  1. public class AdminController : Controller
  2. {
  3. [AntiSqlInject]
  4. public ActionResult Index(string name = "", string loginName = "", int page = 1)
  5. {
  6. ViewBag.Name = name;
  7. ViewBag.LoginName = loginName;
  8. var r = DAdmin.GetList(name, loginName, page, 2);
  9. return View(r);
  10. }
  11. }
需要对Action的参数进行sql检查,只用在前面加上,上面定义的特性类AntiSqlInject。这个特性类可以用在任何的需要防止sql注入的Action上,根本不用对手动的去过滤程序中获取到的所有参数,安全、方便简洁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值