在開發程序的過程中,稍微不注意就會隱含有sql注入的危險。今天我就來說下,ASP.NET mvc 5使用Filter過濾Action參數防止sql注入,讓你代碼安全簡潔。不用每下地方對參數的值都進行檢查,看是用戶輸入的內容是否有危險的sql。如果每個地方都要加有幾個缺點:
1、工作量大
2、容易遺漏
3、不容易維護
下面我通過寫一個過濾防止sql的特性類,對Action執行前對Action的參數進行處理,如果有其值有sql語句,就會這些非法字符替換為空字符串。
一、sql注入的例子:
上面的輸入有兩個輸入框,用戶可以輸入任何的值,包括有sql注入的值。
后台代碼:
AdminController.cs
public class AdminController : Controller { public ActionResult Index(string name = "", string loginName = "", int page = 1) { ViewBag.Name = name; ViewBag.LoginName = loginName; var r = DAdmin.GetList(name, loginName, page, 2); return View(r); } } }
DAdmin.cs:
public class DAdmin { public static PageDataView<MSys_Admin> GetList(string name, string loginName, int page,int pageSize=10) { PageCriteria criteria = new PageCriteria(); 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}%'", loginName); 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注入的字符串輔助類
{ public static string FilterSql(string s) { if (string.IsNullOrEmpty(s)) return string.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; } }
這個類對上面sql相關的字符串都替換掉。
2、定義一個用來檢查並處理Action參數的特性類
public class AntiSqlInjectAttribute:FilterAttribute,IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) { } public void OnActionExecuting(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中的使用
public class AdminController : Controller { [AntiSqlInject] public ActionResult Index(string name = "", string loginName = "", int page = 1) { ViewBag.Name = name; ViewBag.LoginName = loginName; var r = DAdmin.GetList(name, loginName, page, 2); return View(r); } }
需要對Action的參數進行sql檢查,只用在前面加上,上面定義的特性類AntiSqlInject。這個特性類可以用在任何的需要防止sql注入的Action上,根本不用對手動的去過濾程序中獲取到的所有參數,安全、方便簡潔。