ASP.NET MVC: 使用自定义 ModelBinder 过滤敏感信息
昨天發(fā)表了一篇隨筆《ASP.NET MVC: 使用 Filters 附加過濾敏感信息功能》(以下簡稱《Filter過濾》),今天一早醒來發(fā)現(xiàn)一處重大漏洞,于是在發(fā)了一條評論指出存在問題,并希望有朋友能指正。可到現(xiàn)在也沒見有朋友找出問題,索引再發(fā)一篇隨筆,進行更正。
存在的漏洞?
《Filter過濾》一文中使用的代碼如下:?
?1?????public?class?SensitiveWordsFilterAttribute:?ActionFilterAttribute?2?????{
?3?????????public?override?void?OnActionExecuting(ActionExecutingContext?filterContext)
?4?????????{
?5?????????????var?parameters?=?filterContext.ActionDescriptor.GetParameters();
?6?????????????foreach?(var?parameter?in?parameters)
?7?????????????{
?8?????????????????if?(parameter.ParameterType?==?typeof(string))
?9?????????????????{
10?????????????????????//獲取字符串參數(shù)原值
11?????????????????????var?orginalValue?=?filterContext.ActionParameters[parameter.ParameterName]?as?string;
12?????????????????????//使用過濾算法處理字符串
13?????????????????????var?filteredValue?=?SensitiveWordsFilter.Instance.Filter(orginalValue);
14?????????????????????//將處理后值賦給參數(shù)
15?????????????????????filterContext.ActionParameters[parameter.ParameterName]?=?filteredValue;
16?????????????????}
17?????????????}
18?????????}
19?????}
?問題在第8行,SensitiveWordsFilterAttribute 目前只能對字符串類型這樣的簡單數(shù)據(jù)進行過濾,沒有考慮到復雜類型,對下面代碼就則無法實現(xiàn)過濾:
1?????public?class?ArticlesController?:?Controller2?????{
3?????????[HttpPost]
4?????????public?ActionResult?Create(Article?article)
5?????????{
6?????????????//...
7?????????}
8?????????//...
9?????}
?Article是一個自定義類:
1?????public?class?Article:?DomainModel2?????{
3?????????public?int?ID?{?get;?set;?}
4?????????public?string?Title?{?get;?set;?}
5?????????public?string?Content?{?get;?set;?}
6?????????public?DateTime?CreationTime?{?get;?set;?}
7?????}
SensitiveWordsFilterAttribute 對自定義類型是不太好處理的,當然也有解決辦法,如使用反射遍歷訪問Article的每一個字符串屬性,進行過濾。
本文采用 ASP.NET MVC Model Binding 來實現(xiàn)目標。
?ASP.NET MVC Model Binding
?在ASP.NET MVC中,我們可以使用下面的方式來接收用戶提交的數(shù)據(jù):
?1?????public?class?ArticlesController?:?Controller?2?????{
?3?????????public?ActionResult?Query(string?title,?DateTime??creationDate)
?4?????????{
?5?????????????//...
?6?????????}
?7?????????[HttpPost]
?8?????????public?ActionResult?Create(Article?article)
?9?????????{
10?????????????//...
11?????????}
12?????}
??這得益于 ASP.NET MVC ModelBinding 特性。使用這個特性,我們無需再使用?Request.Form["title"] 從 HTTP 請求中獲取數(shù)據(jù),也不需要再使用 DateTime.Parse() 或 DateTime.TryParse()?方法進行類型轉(zhuǎn)換,也不再需要對實例的每一個屬性逐一賦值。ModelBinding 特性將我們從這些無聊的低級工作中解放了出來,讓我們專心去做高級的工作。
如上面代碼所示,ModelBinding 既可以綁定簡單數(shù)據(jù)類型,也可以綁定自定義類型,還可以綁定數(shù)組、集合、字典、二進制數(shù)據(jù)(byte[]),甚至還能用來接收文件上傳。
ModelBinding 在綁定自定義類型時,還能夠有選擇的綁定指定屬性或排除指定屬性:?
1?????public?ActionResult?Create([Bind(Include?=?"Name,?Sex,?Birthday")]?Person?person)?2?????{?
3?????????//?...?
4?????}?
5?????public?ActionResult?Create([Bind(Exclude?=?"ID")]?Person?person)?
6?????{?
7?????????//?...?
8?????}
?ASP.NET MVC ModelBinding 的功能相當完善,實現(xiàn)也比較復雜,具體是由 DefaultModelBinder 類來完成的。對于一些特定功能(如本文中的敏感信息過濾)可通過擴展 DefaultModelBinder 類的功能來實現(xiàn)。
具有敏感信息過濾功能 ModelBinder
?在面向?qū)ο蟮氖澜缰?#xff0c;擴展功能最簡單的方式就是繼承。我們新建一個類 SensitiveWordsFilterModelBinder,繼承自 DefaultModelBinder,重寫 SetProperty 和 BindModel?方法,如下:
?1?????public?class?SensitiveWordsFilterModelBinder?:?DefaultModelBinder?2?????{
?3?????????protected?override?void?SetProperty(ControllerContext?controllerContext,?
?4?????????????ModelBindingContext?bindingContext,?PropertyDescriptor?propertyDescriptor,?object?value)
?5?????????{
?6?????????????if?(propertyDescriptor.PropertyType?==?typeof(string)/*?&&?value?is?string*/)
?7?????????????????value?=?SensitiveWordsFilter.Instance.Filter(value?as?string);
?8?????????????base.SetProperty(controllerContext,?bindingContext,?propertyDescriptor,?value);
?9?????????}
10?????????public?override?object?BindModel(ControllerContext?controllerContext,?ModelBindingContext?bindingContext)
11?????????{
12?????????????var?value?=?base.BindModel(controllerContext,?bindingContext);
13?????????????if(bindingContext.ModelType?==?typeof(string)/*?&&?value?is?string*/)
14?????????????????value?=?SensitiveWordsFilter.Instance.Filter(value?as?string);
15?????????????return?value;
16?????????}
17?????}
?重寫 SetProperty 方法(3~9行)用來對自定義類型進行敏感信息過濾:對自定義類型來說,數(shù)據(jù)綁定主要針對屬性,所有屬性綁定完成,自定義類型的實例也就綁定完成了。重寫 SetProperty 就是在給 string 類型的屬性賦值前,增加敏感信息過濾這一步操作。相對使用 SensitiveWordsFilterAttribute + 反射 的方式處理自定義類型,SensitiveWordsFilterModelBinder 更加合理,效率也要高些。重寫 SetProperty 時,可以通過 bindingContext.ModelType 獲取所在類的類型,也可以通過 propertyDescriptor 獲取當前屬性的信息,還可以通過controllerContext獲取當前controller的信息,通過這三個屬性,我們可以有選擇的進行過濾操作,以提高效率。
重寫 BindModel 方法(10~16行)用來對 string 類型進行敏感信息過濾,string 是簡單數(shù)據(jù)庫類型,對它進行綁定時不會調(diào)用 SetProperty 方法,因此要單獨進行處理。
僅僅有這個 ModelBinder 是不夠的,MVC不知道什么情況下使用它,因此我們還要進行配置,使 SensitiveWordsFilterModelBinder 生效。
配置使用 SensitiveWordsFilterModelBinder
方式一:直接在參數(shù)上使用
1??????public?ActionResult?Create([ModelBinder(typeof(SensitiveWordsFilterModelBinder))]Article?article)2??????{
3??????????return?null;
4??????}
5??????public?ActionResult?Create([ModelBinder(typeof(SensitiveWordsFilterModelBinder))]string?title,
6??????????????????[ModelBinder(typeof(SensitiveWordsFilterModelBinder))]string?content,?DateTime??creationTime)
7??????{
8??????????return?null;
9??????}
?使用這種方式比較“ugly”,尤其是 ModelBinder 名字比較長的時候。這種方式的最大缺點是需要對每個參數(shù)進行標記。
方式二:標記在 Model 上?
1?????[ModelBinder(typeof(SensitiveWordsFilterModelBinder))]2?????public?class?Article:?DomainModel
3?????{
4?????????//...
5?????}
這種比較不錯,只需在 Article 類上標記一次,所有 Controller 中的 Action 的 Article?類型的參數(shù)都將使用 SensitiveWordsFilterModelBinder。
但這種方式僅對自定義類型有效,對系統(tǒng)定義的類型,如:string,我們是很難給它加上 Attribute 的。
?方式三:在 Global.asax.cs 文件中處理:
1?????protected?void?Application_Start()2?????{
3?????????ModelBinders.Binders.Add(typeof(Article),?new?SensitiveWordsFilterModelBinder());
4?????????ModelBinders.Binders.Add(typeof(string),?new?SensitiveWordsFilterModelBinder());
5?????}
如上面代碼,我們可為每一種類型,設(shè)置一個 ModerBinder。也可以像下面這樣進行批量設(shè)置:
1??????protected?void?Application_Start()2??????{
3??????????var?sensitiveWordsFilterModelBinder?=?new?SensitiveWordsFilterModelBinder();
4??????????var?types?=?typeof(Article).Assembly.GetTypes().Where(t=>t.IsSubclassOf(typeof(DomainModel)));
5??????????foreach?(var?type?in?types)
6??????????????ModelBinders.Binders.Add(type,?sensitiveWordsFilterModelBinder);
7??????}
這個就不多解釋了。
使用 SensitiveWordsFilterModelBinder 方式的缺點
?有些 MVC 的初學者之前大多是做 ASP.NET,可能有時會使用 Request.Form["..."] 這種方式來接收數(shù)據(jù),使用這種方式的地方都會成為系統(tǒng)的漏洞。
總結(jié)
ASP.Net MVC 采用了非常先進的設(shè)計思想,具有良好的可擴展性,可以通過各種方式輕松解決我們遇到的各種問題。
轉(zhuǎn)載于:https://www.cnblogs.com/ldp615/archive/2010/07/30/SensitiveWordsFilterModelBinder.html
總結(jié)
以上是生活随笔為你收集整理的ASP.NET MVC: 使用自定义 ModelBinder 过滤敏感信息的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 法学教授:洋文凭情结是对教育体制的嘲弄
- 下一篇: 使用CallableStatement处