C# 檢查字符串,防SQL注入攻擊

 

看到CSDN上好多關於防SQL注入的貼子,整理了一下
C# 防SQL 注入:
http://topic.csdn.net/u/20080510/16/29c515de-c4d2-41fe-a1dc-df84de18f9b7.html
http://hi.baidu.com/blueyund/blog/item/1545d1a2829b74aacaefd00d.html
/// <summary>
/// 檢測是否含有危險字符(防止Sql注入)
/// </summary>
/// <param name="contents">預檢測的內容</param>
/// <returns>返回True或false</returns>
private bool HasDangerousContents(string contents)
{
bool bReturnValue = false;
if (contents.Length > 0)
{
//convert to lower
string sLowerStr = contents.ToLower();
//RegularExpressions
string sRxStr = @"(/sand/s)|(/sand/s)|(/slike/s)|(select/s)|(insert/s)|

(delete/s)|(update/s[/s/S].*/sset)|(create/s)|(/stable)|(<[iframe|/iframe|script|/script])|

(')|(/sexec)|(/sdeclare)|(/struncate)|(/smaster)|(/sbackup)|(/smid)|(/scount)";
//Match
bool bIsMatch = false;
System.Text.RegularExpressions.Regex sRx = new

System.Text.RegularExpressions.Regex(sRxStr);
bIsMatch = sRx.IsMatch(sLowerStr, 0);
if (bIsMatch)
{
bReturnValue = true;
}
}
return bReturnValue;
}



在解決SQL Injection的可行方案中,基於正則表達式的方案不予考慮,理由有:
1、即使使用了RegexOptions.Compile選項,正則表達式的性能也不很理想,尤其是在樓主“流量巨大”

的網站中很可能會造成性能瓶頸。
2、過濾的範圍很難把握,不是過寬就是過窄。對樓主的這個例子來說,我的文章中有一個" and "都會被

判斷爲危險字符串;另一方面,這個表達式對"exec"開頭的字符串卻無能爲力。當然如果樓主的這個表達

式可以只是針對某一個或幾個參數進行驗證,這樣卻必須保證對所有其他的輸入參數都寫對應的表達式來

過濾。

可以使用的方案主要有:
1、使用SqlParameter類
2、在數據庫上增加一個抽象層次,防止直接對數據庫的操作
3、在數據庫方面,應用程序使用專門的帳戶,設置其對應的權限,一定不要用管理員
4、避免拼接字符串

如果實在沒有法要用到拼接,就用SP_EXECUTESQL 系統存儲過程防止SQL注入
例如:

SQL code

declare @userid int set @userid = 1 declare @sqlStr nvarchar(1000),@param nvarchar(400)

set @sqlStr='select * from table where [userid]=@tuserid' //這裏可以拼接字符串,我這裏簡單點

哈 set @param='@tuserid int' execute sp_executesql @sqlstr,@param,@tuserid=@userid //變量替




這種方式的字符串並接就不會有SQL注入的問題。

string sRxStr = @"(/sand/s) ¦(/sand/s) ¦(/slike/s) ¦(select/s) ¦(insert/s) ¦(delete/s) ¦

(update/s[/s/S].*/sset) ¦(create/s) ¦(/stable) ¦( <[iframe ¦/iframe ¦script ¦/script]) ¦(')

¦(/sexec) ¦(/sdeclare) ¦(/struncate) ¦(/smaster) ¦(/sbackup) ¦(/smid) ¦(/scount)";


近日有無聊人士對我們一個學術性網站進行了Sql注入攻擊,造成網站無法被正常訪問。
分析Sql注入攻擊的原理不難知道主要還是在網站編制過程中沒有考慮防此類攻擊的有效性驗證,同時說

明使用存儲過程在防止此類攻擊有很好的效果,因爲通常它會對輸入參數進行類型轉化,這些參數只可能

是字段值,而不會被理解爲sql語句中的一部分。當然有些網站在開發過程中並沒有考慮這種防範措施,

改起代碼來工作量比較大,網上有很多方法,我整理了一下,測試的效果還可以,供參考,在此不標明原

始出處了。
此類方法就是在全局Application類的Application_BeginRequest方法中對用戶輸入的數據進行過濾,濾

去不應該出現在地址欄中的Sql敏感單詞。
一、若aps.net工程中沒有全局類,則新建一個全局應用程序類;
二、爲此類添加以下方法,SqlStr就是要屏蔽的Sql關鍵字,可以根據需要變化其中內容。
private bool ProcessSqlStr(string Str)
{
bool ReturnValue = true;
try
{
if (Str != "")
{
string SqlStr =

"select*|and'|or'|insertinto|deletefrom|altertable|update|createtable|createview|dropview|cr

eateindex|dropindex|createprocedure|dropprocedure|createtrigger|droptrigger|createschema|dro

pschema|createdomain|alterdomain|dropdomain|);|select@|declare@|print@|char(|select";
string[] anySqlStr = SqlStr.Split('|');
foreach (string ss in anySqlStr)
{
if (Str.IndexOf(ss) >= 0)
{
ReturnValue = false;
}
}
}
}
catch
{
ReturnValue = false;
}
return ReturnValue;
}
三、爲Application類添加Application_BeginRequest方法,如下:
protected void Application_BeginRequest(Object sender, EventArgs e)
{
////遍歷Post參數,隱藏域除外
//foreach (string i in this.Request.Form)
//{
// if (i == "__VIEWSTATE") continue;
// this.goErr(this.Request.Form[i].ToString());
//}
////遍歷Get參數。
//foreach (string i in this.Request.QueryString)
//{
// this.goErr(this.Request.QueryString[i].ToString());
//}
try
{
string getkeys = "";
string sqlErrorPage = System.Configuration.ConfigurationSettings.AppSettings

["CustomErrorPage"].ToString();
if (System.Web.HttpContext.Current.Request.QueryString != null)
{

for (int i = 0; i <

System.Web.HttpContext.Current.Request.QueryString.Count; i++)
{
getkeys = System.Web.HttpContext.Current.Request.QueryString.Keys[i];
if (!ProcessSqlStr(System.Web.HttpContext.Current.Request.QueryString

[getkeys]))
{
System.Web.HttpContext.Current.Response.Redirect(sqlErrorPage + "?

errmsg=sqlserver&sqlprocess=true");
System.Web.HttpContext.Current.Response.End();
}
}
}
if (System.Web.HttpContext.Current.Request.Form != null)
{
for (int i = 0; i < System.Web.HttpContext.Current.Request.Form.Count; i++)
{
getkeys = System.Web.HttpContext.Current.Request.Form.Keys[i];
if (!ProcessSqlStr(System.Web.HttpContext.Current.Request.Form

[getkeys]))
{
System.Web.HttpContext.Current.Response.Redirect(sqlErrorPage + "?

errmsg=sqlserver&sqlprocess=true");
System.Web.HttpContext.Current.Response.End();
}
}
}
}
catch
{
// 錯誤處理: 處理用戶提交信息!
}
}
四、建立一個錯誤警告頁,將可疑輸入定向到錯誤頁,如ErrorPage.html
在web.config中加入的 <appSettings>中加入參數
<add key="CustomErrorPage" value="../ErrorPage.html" />
五、關鍵還是在於要寫安全的代碼,合理使用存儲過程。




和我之前遇到的問題一樣,主要是程序上有漏洞,
儘可能全的過濾SQL敏感的語句,
先把數據庫裏面注入的代碼替換掉,
再在Global文件裏裏加入
protected void Application_BeginRequest(Object sender, EventArgs e)
{
//SQL防注入
string Sql_1 =

"exec|insert+|select+|delete+|update+|count|chr|mid|master+|truncate|char|declare|drop+|drop

+table|creat+|creat+table";
string Sql_2 = "exec+|insert|insert+|delete+|update+|count(|count+|chr+|+mid

(|+mid+|+master+|truncate+|char+|+char(|declare+|drop+|creat+|drop+table|creat+table";
string[] sql_c = Sql_1.Split('|');
string[] sql_c1 = Sql_2.Split('|');

if (Request.QueryString != null)
{
foreach (string sl in sql_c)
{
if (Request.QueryString.ToString().ToLower().IndexOf(sl.Trim()) >= 0)
{
Response.Write("警告!你的IP已經被記錄!不要使用敏感字符!");//
Response.Write(sl);
Response.Write(Request.QueryString.ToString());
Response.End();
break;
}
}
}

if (Request.Form.Count > 0)
{
string s1 = Request.ServerVariables["SERVER_NAME"].Trim();//服務器名稱
if (Request.ServerVariables["HTTP_REFERER"] != null)
{
string s2 = Request.ServerVariables["HTTP_REFERER"].Trim();//http接收的名稱
string s3 = "";
if (s1.Length > (s2.Length - 7))
{
s3 = s2.Substring(7);
}
else
{
s3 = s2.Substring(7, s1.Length);
}
if (s3 != s1)
{
Response.Write("警告!你的IP已經被記錄!不要使用敏感字符!");//
Response.End();
}
}
}
}

http://zhidao.baidu.com/question/55294652.html
http://www.cnblogs.com/yiki/default.html?page=9

/// <summary>
/// 校驗參數是否存在SQL字符
/// </summary>
/// <param name="tm"></param>
private void goErr(string tm)
{
if (![color=#FF0000]SqlHelper.checkSql([/color]tm))
this.Response.Redirect("/error.html"); }
/// <summary>
/// 當有數據時交時,觸發事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Application_BeginRequest(Object sender, EventArgs e)
{
//遍歷Post參數,隱藏域除外
foreach (string i in this.Request.Form)
{
if (i == "__VIEWSTATE") continue;
this.goErr(this.Request.Form[i].ToString());
}
//遍歷Get參數。
foreach (string i in this.Request.QueryString)
{
this.goErr(this.Request.QueryString[i].ToString());
}
}
APPCODE文件夾裏寫個類加一個方法
/// <summary>
/// 檢查字符串是否包含特殊字符
/// </summary>
/// <param name="sql">要檢查的字符串</param>
/// <returns>返回BOOL</returns>
public static bool checkSql(string sql)
{
bool chk = true;
string[] Lawlesses ={ "=", "'", ";", ",", "(", ")", "%", "-", "#","select" };
if (Lawlesses == null || Lawlesses.Length <= 0)
return true;
string str_Regex = ".*[";
for (int i = 0; i < Lawlesses.Length - 1; i++)
str_Regex += Lawlesses[i] + "|"; str_Regex += Lawlesses[Lawlesses.Length - 1] + "].*";
if (Regex.Matches(sql, str_Regex).Count > 0)
chk = false; return chk;
}

http://blog.atimg.com/article/jswz/1521.htm
http://technet.microsoft.com/zh-cn/cc562985.aspx
解放WEB程序員的輸入驗證:
http://www.cnblogs.com/ttyp/archive/2005/04/06/132727.html
http://www.cnblogs.com/ttyp/archive/2005/01/13/91592.html



using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace DataSecurity
{
class DataSecurity
{
//參數中的非法字符串
public static string tabooStr =

"SELECT|INSERT|DELETE|UPDATE|AND|OR|EXEC|TRUNCATE|DECLARE|JOIN|=|%|'";
/// <summary>
/// 驗證頁面之間傳遞的參數是否有非法的字符串,以防止sql注入
/// </summary>
/// <param name="param">頁面之間傳遞的參數</param>
/// <returns>有返回true,否則返回false</returns>
///備註:在Global.aspx中的Request_Begin中調用此方法,如果有非法參數,轉向錯誤頁面
/* Global.aspx的Request_Begin
* 判斷通過POST方式傳遞的所有參數: foreach(string param in this.Request.Form){ . . .}
* 判斷通過GET方式傳遞的所有參數:foreach(string param in this.Request.Query){ . . .}
*/
public static bool ValidateSql(string param)
{
bool result = false;
if (!string.IsNullOrEmpty(param))
{
foreach (string str in tabooStr.Split('|'))
{
if (param.ToUpper().IndexOf(str) > -1)
{ result = true; break; }
}
}
return result;
}
/// <summary>
/// 過濾掉頁面之間傳遞參數中的非法字符串
/// </summary>
/// <param name="param">頁面之間傳遞的參數</param>
/// <returns>返回過濾後的字符串</returns>
public static string FilterSql(string param)
{
return Regex.Replace(param, tabooStr, "**", RegexOptions.IgnoreCase);
}
}
}


其實這裏給了兩種思路,
第一種就是在Global.asax中設置(詳細見第一個方法的註釋),另外一種就是在每次獲得上一頁面傳遞

的參數的時候調用FilterSql()方法,過濾掉有可能是Sql注入的參數
嗯 ,雖然有點碎,不過,總的來說,也就只有這些方法了吧。嗯 ,如有高手路過還請指點一下,近來我這有個網站總被注入,好無奈。我Global.asax設置了,也不行,奇怪。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章