SQL Server T-SQL篇如何防止SQL注入的解决方法
这篇文章主要为大家详细介绍了SQL Server T-SQL篇如何防止SQL注入的解决方法,具有一定的参考价值,可以用来参考一下。
对此感兴趣的朋友,看看idc笔记做的技术笔记!
1.什么是SQL注入所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击。2.怎么进行SQL注入关于怎么进行SQL注入,网上已经有很多文章详细介绍过了,可以参考博友滴答的雨的博文 《SQL注入攻防入门详解》,亲测有效。当执行完文中的5、6、7三步的时候,你会发现服务器上的安全保护措施都已是浮云,服务器也因此变成了名副其实的“肉机”。下面附上一张我在本机执行完文中描述的脚本后的效果截图(Win8 x64 操作系统):【图片暂缺】微软的“不禁止即允许(Not forbidden is allow)”的做法使得操作系统像是服务器所穿的镂空礼物一样,美观但却有很多“漏洞”。好了,现在此小黑已经拥有了服务器的管理员权限,很显然元芳怎么看已经不重要了。3.如何防止SQL注入的发生滴答的雨已经在博文详细阐述了SQL Server数据库如何进行防注入的操作,这里不再赘述。这一篇我主要说一下对于一个使用拼接SQL进行查询操作的Web应用,怎么进行防注入操作。先说一些前提,为什么我们要使用拼接SQL的方式进行查询?偷懒呗。这在开发过程中,看似省去了编写参数化部分的代码量,节省了时间和精力。但这样做的结果就是应用的安全性大打折扣,而且拼SQL方式创建的应用,后期的维护难度也很大。SQL参数化查询是最简单有效的避免SQL注入的解决方案,目前主流的ORM框架(MyBatis.NET/NHibernate/EntityFramework)都内置支持并且推荐使用这种方式进行持久层封装。然而有数据库不支持参数化查询怎么办?是的,你没有看错,确实有这样的数据库存在。吐个槽先,个人认为,一切不支持参数化查询的数据库都是在“耍流氓”,这种天然的缺陷会让小黑们肆无忌惮地去“非礼”服务器,至少是数据库本身。在这样的情况下,我觉得其他功能做得再好也只能算是花拳绣腿,连最基本的数据都保护不了,那不等同于将劳动成果拱手让人。按照存在即合理的逻辑,我们暂且认为它是合理的。来说说我目前的做法,基于上述数据库创建的Web应用,拼接SQL操作已经渗透到站点的每个页面、每个用户控件,所以我采用的方式是请求过滤。下面是防SQL注入的操作类:
1 | 1: /// <summary> |
1 | 2: ///SqlInject 的摘要说明 |
1 | 3: /// </summary> |
1 | 4: public class SqlInject : System.Web.UI.Page |
1 | 5: { |
1 | 6: //检测到注入后的处理方式: 0:仅警告;1:警告+记录;2:警告+自定义错误页面;3:警告+记录+自定义错误页面 |
1 | 7: private const int _type = 0; |
1 | 8: private const string errRedirectPage = "/err.aspx" ; |
1 |
1 | 10: //如果记录注入信息,那么请设置:errMDBpath:数据库路径 |
1 | 11: private const string errMDBpath = "/SqlInject.mdb" ; |
1 | 12: |
1 | 13: |
1 | 14: //过滤特征字符 |
1 | 15: //过滤特征字符 |
1 | 16: private static string StrKeyWord = ConfigurationManager.AppSettings[ "SqlKeyWord" ]; //@"select|insert|delete|from|count(|drop table|update|truncate|asc(|mid(|char(|xp_cmdshell|exec|master|net local group administrators|net user|or|and"; |
1 | 17: private static string StrRegex = ConfigurationManager.AppSettings[ "SqlRegex" ]; //@";|/|(|)|[|]|{|}|%|@|*|'|!"; // 原始过滤条件:【-|;|,|/|(|)|[|]|{|}|%|@|*|'|!】 |
1 | 18: |
1 | 19: private HttpRequest request; |
1 | 20: public SqlInject(System.Web.HttpRequest _request) |
1 | 21: { |
1 | 22: this.request = _request; |
1 | 23: } |
1 | 24: ///<summary> |
1 | 25: ///检测SQL注入及记录、显示出错信息 |
1 | 26: ///</summary> |
1 | 27: public void CheckSqlInject() |
1 | 28: { |
1 | 29: bool isInject = false; |
1 | 30: if (CheckRequestQuery() || CheckRequestForm()) |
1 | 31: { |
1 | 32: isInject = true; |
1 | 33: } |
1 | 34: else |
1 | 35: { |
1 | 36: return ; |
1 | 37: } |
1 | 38: |
1 | 39: switch (_type) |
1 | 40: { |
1 | 41: case 0: |
1 | 42: ShowErr(); |
1 | 43: break ; |
1 | 44: case 1: |
1 | 45: ShowErr(); |
1 | 46: SaveToMdb(); |
1 | 47: break ; |
1 | 48: case 2: |
1 | 49: ShowErr(); |
1 | 50: string temp; |
1 | 51: System.Web.HttpContext.Current.Response.Write( "<script>setTimeout(\"" + "location.href='" + errRedirectPage + "'" + "\",5000)</script>" ); |
1 | 52: break ; |
1 | 53: case 3: |
1 | 54: ShowErr(); |
1 | 55: SaveToMdb(); |
1 | 56: System.Web.HttpContext.Current.Response.Write( "<script>setTimeout(\"" + "location.href='" + errRedirectPage + "'" + "\",5000)</script>" ); |
1 | 57: break ; |
1 | 58: default : |
1 | 59: break ; |
1 | 60: } |
1 | 61: System.Web.HttpContext.Current.Response. End (); |
1 | 62: |
1 | 63: } |
1 | 64: private void SaveToMdb() |
1 | 65: { |
1 | 66: OleDbConnection conn = new OleDbConnection( "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + Server.MapPath(errMDBpath)); |
1 | 67: conn.Open(); |
1 | 68: OleDbCommand cmd = conn.CreateCommand(); |
1 | 69: |
1 | 70: cmd.CommandText = "insert into [Record] (sIP,sDate,sPath) values ('" + |
1 | 71: request.ServerVariables[ "REMOTE_ADDR" ].ToString() + "','" + |
1 | 72: DateTime.Now + "','" + request.ServerVariables[ "URL" ].ToLower() + RelaceSingleQuotes(request.QueryString.ToString()) + "')" ; |
1 | 73: int code = cmd.ExecuteNonQuery(); |
1 | 74: if (code == 1) |
1 | 75: System.Web.HttpContext.Current.Response.Write( "<br>****以上信息已记录至日志数据库****" ); |
1 | 76: else |
1 | 77: System.Web.HttpContext.Current.Response.Write( "<br>日志数据库出错" ); |
1 | 78: conn.Close(); |
1 | 79: |
1 | 80: } |
1 | 81: private string RelaceSingleQuotes(string _url) |
1 | 82: { |
1 | 83: string URL = _url.Replace( "'" , "单引号" ); |
1 | 84: return URL; |
1 | 85: } |
1 | 86: private void ShowErr() |
1 | 87: { |
1 | 88: //string msg = @"<font color=red>请不要尝试未授权之入侵检测!</font>" + @"<br><br>"; |
1 | 89: //msg += @"操作IP:" + request.ServerVariables["REMOTE_ADDR"] + @"<br>"; |
1 | 90: //msg += @"操作时间:" + DateTime.Now + @"<br>"; |
1 | 91: //msg += @"页面:" + request.ServerVariables["URL"].ToLower() + request.QueryString.ToString() + @"<br>"; |
1 | 92: //msg += @"<a href='#' onclick='javascript:window.close()'>关闭</a>"; |
1 | 93: //System.Web.HttpContext.Current.Response.Clear(); |
1 | 94: //System.Web.HttpContext.Current.Response.Write(msg); |
1 | 95: System.Web.HttpContext.Current.Response.Write( "<script>alert('请不要尝试未授权之入侵检测!');javascript:history.go(-1);</script>" ); |
1 | 96: } |
1 | 97: ///<summary> |
1 | 98: /// 特征字符 |
1 | 99: ///</summary> |
1 | 100: public static string KeyWord |
1 | 101: { |
1 | 102: get |
1 | 103: { |
1 | 104: return StrKeyWord; |
1 | 105: } |
1 | 106: } |
1 | 107: ///<summary> |
1 | 108: /// 特征符号 |
1 | 109: ///</summary> |
1 | 110: public static string RegexString |
1 | 111: { |
1 | 112: get |
1 | 113: { |
1 | 114: return StrRegex; |
1 | 115: } |
1 | 116: } |
1 | 117: |
1 | 118: ///<summary> |
1 | 119: ///检查字符串中是否包含Sql注入关键字 |
1 | 120: /// <param name="_key">被检查的字符串</param> |
1 | 121: /// <returns>如果包含注入true;否则返回false</returns> |
1 | 122: ///</summary> |
1 | 123: private static bool CheckKeyWord(string _key) |
1 | 124: { |
1 | 125: string[] pattenString = StrKeyWord.Split( '|' ); |
1 | 126: string[] pattenRegex = StrRegex.Split( '|' ); |
1 | 127: foreach (string sqlParam in pattenString) |
1 | 128: { |
1 | 129: if (_key.Contains(sqlParam + " " ) || _key.Contains( " " + sqlParam)) |
1 | 130: { |
1 | 131: return true; |
1 | 132: } |
1 | 133: } |
1 | 134: foreach (string sqlParam in pattenRegex) |
1 | 135: { |
1 | 136: if (_key.Contains(sqlParam)) |
1 | 137: { |
1 | 138: return true; |
1 | 139: } |
1 | 140: } |
1 | 141: return false; |
1 | 142: |
1 | 143: } |
1 | 144: ///<summary> |
1 | 145: ///检查URL中是否包含Sql注入 |
1 | 146: /// <param name="_request">当前HttpRequest对象</param> |
1 | 147: /// <returns>如果包含注入true;否则返回false</returns> |
1 | 148: ///</summary> |
1 | 149: public bool CheckRequestQuery() |
1 | 150: { |
1 | 151: if (request.QueryString. Count > 0) |
1 | 152: { |
1 | 153: foreach (string sqlParam in this.request.QueryString) |
1 | 154: { |
1 | 155: if (sqlParam == "__VIEWSTATE" ) continue ; |
1 | 156: if (sqlParam == "__EVENTVALIDATION" ) continue ; |
1 | 157: if (CheckKeyWord(request.QueryString[sqlParam].ToLower())) |
1 | 158: { |
1 | 159: return true; |
1 | 160: } |
1 | 161: } |
1 | 162: } |
1 | 163: return false; |
1 | 164: } |
1 | 165: ///<summary> |
1 | 166: ///检查提交的表单中是否包含Sql注入 |
1 | 167: /// <param name="_request">当前HttpRequest对象</param> |
1 | 168: /// <returns>如果包含注入true;否则返回false</returns> |
1 | 169: ///</summary> |
1 | 170: public bool CheckRequestForm() |
1 | 171: { |
1 | 172: if (request.Form. Count > 0) |
1 | 173: { |
1 | 174: foreach (string sqlParam in this.request.Form) |
1 | 175: { |
1 | 176: if (sqlParam == "__VIEWSTATE" ) continue ; |
1 | 177: if (sqlParam == "__EVENTVALIDATION" ) continue ; |
1 | 178: if (CheckKeyWord(request.Form[sqlParam])) |
1 | 179: { |
1 | 180: return true; |
1 | 181: } |
1 | 182: } |
1 | 183: } |
1 | 184: return false; |
1 | 185: } |
1 | 186: } |
过滤类是在某前辈的作品基础上改的,很抱歉我已经找不到最原始的出处了。需要在Web.Config中添加防SQL注入的特征字符集:
代码如下:
1 2 3 4 5 | <code> <!--防SQL注入时的特征字符集--> <add key= "SqlKeyWord" value= "select|insert|delete|from|count(|drop table|update|truncate|asc(|mid(|char(|xp_cmdshell|exec|master|net local group administrators|net user|or|and" /> <add key= "SqlRegex" value= ";|(|)|[|]|{|}|%|@|*|'|!" /> </code> |
代码如下:
1 2 3 4 5 6 7 8 | <code> protected void Application_BeginRequest(object sender, EventArgs e) { //防SQL注入代码 SqlInject myCheck = new SqlInject(this.Request); myCheck.CheckSqlInject(); } </code> |
注:关于SQL Server T-SQL篇如何防止SQL注入的解决方法的内容就先介绍到这里,更多相关文章的可以留意