AOP實踐--ASP.NET MVC 5使用Filter過濾Action引數防止sql注入,讓你程式碼安全簡潔
1、工作量大
2、容易遺漏
3、不容易維護
下面我通過寫一個過濾防止sql的特性類,對Action執行前對Action的引數進行處理,如果有其值有sql語句,就會這些非法字元替換為空字串。
一、sql注入的例子:
上面的輸入有兩個輸入框,使用者可以輸入任何的值,包括有sql注入的值。
後臺程式碼:
AdminController.cs
- public
- {
- publicActionResultIndex(string name ="",string loginName ="",int page =1)
- {
- ViewBag.Name= name;
- ViewBag.LoginName= loginName;
- var r =DAdmin.GetList(name, loginName, page,2);
- returnView(r);
- }
- }
- }
- publicclassDAdmin
- {
- publicstaticPageDataView<MSys_Admin>GetList(string
- {
- PageCriteria criteria =newPageCriteria();
- criteria.Condition="1=1";
- if(!string.IsNullOrEmpty(name))
- criteria.Condition+=string.Format(" and Name like '%{0}%'", name);
- if(!string.IsNullOrEmpty(loginName))
- criteria.Condition+=string.Format(" and LoginName like '%{0}%'"
- criteria.CurrentPage= page;
- criteria.Fields="*";
- criteria.PageSize= pageSize;
- criteria.TableName="Sys_Admin a";
- criteria.PrimaryKey="UID";
- var r =Common.GetPageData<MSys_Admin>(criteria);
- return r;
- }
- }
上面對使用者輸入的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注入的字串輔助類
- publicclassStringHelper
- {
- publicstaticstringFilterSql(string s)
- {
- if(string.IsNullOrEmpty(s))returnstring.Empty;
- s = s.Trim().ToLower();
- s =ClearScript(s);
- s = s.Replace("=","");
- s = s.Replace("'","");
- s = s.Replace(";","");
- s = s.Replace(" or ","");
- s = s.Replace("select","");
- s = s.Replace("update","");
- s = s.Replace("insert","");
- s = s.Replace("delete","");
- s = s.Replace("declare","");
- s = s.Replace("exec","");
- s = s.Replace("drop","");
- s = s.Replace("create","");
- s = s.Replace("%","");
- s = s.Replace("--","");
- return s;
- }
- }
2、定義一個用來檢查並處理Action引數的特性類
- publicclassAntiSqlInjectAttribute:FilterAttribute,IActionFilter
- {
- publicvoidOnActionExecuted(ActionExecutedContext filterContext)
- {
- }
- publicvoidOnActionExecuting(ActionExecutingContext filterContext)
- {
- var actionParameters = filterContext.ActionDescriptor.GetParameters();
- foreach(var p in actionParameters)
- {
- if(p.ParameterType==typeof(string))
- {
- if(filterContext.ActionParameters[p.ParameterName]!=null)
- {
- filterContext.ActionParameters[p.ParameterName]=StringHelper.FilterSql(filterContext.ActionParameters[p.ParameterName].ToString());
- }
- }
- }
- }
- }
說明:這個特性類是繼承了類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中的使用
- publicclassAdminController:Controller
- {
- [AntiSqlInject]
- publicActionResultIndex(string name ="",string loginName ="",int page =1)
- {
- ViewBag.Name= name;
- ViewBag.LoginName= loginName;
- var r =DAdmin.GetList(name, loginName, page,2);
- returnView(r);
- }
- }