您的位置:首页 > 数据库

C# 检查字符串,防SQL注入攻击

2009-08-19 11:29 260 查看
看到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设置了,也不行,奇怪。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: