zl程序教程

您现在的位置是:首页 >  后端

当前栏目

防SQL注入生成参数化的通用分页查询语句

注入SQL 查询 语句 参数 生成 分页 通用
2023-06-13 09:14:23 时间
使用这种通用的存储过程进行分页查询,想要防SQL注入,只能对输入的参数进行过滤,例如将一个单引号“"”转换成两个单引号“""”,但这种做法是不安全的,厉害的黑客可以通过编码的方式绕过单引号的过滤,要想有效防SQL注入,只有参数化查询才是最终的解决方案。但问题就出在这种通用分页存储过程是在存储过程内部进行SQL语句拼接,根本无法修改为参数化的查询语句,因此这种通用分页存储过程是不可取的。但是如果不用通用的分页存储过程,则意味着必须为每个具体的分页查询写一个分页存储过程,这会增加不少的工作量。
经过几天的时间考虑之后,想到了一个用代码来生成参数化的通用分页查询语句的解决方案。代码如下:
复制代码代码如下:

publicclassPagerQuery
{
privateint_pageIndex;
privateint_pageSize=20;
privatestring_pk;
privatestring_fromClause;
privatestring_groupClause;
privatestring_selectClause;
privatestring_sortClause;
privateStringBuilder_whereClause;
publicDateTimeDateFilter=DateTime.MinValue;
protectedQueryBase()
{
_whereClause=newStringBuilder();
}
/**////<summary>
///主键
///</summary>
publicstringPK
{
get{return_pk;}
set{_pk=value;}
}
publicstringSelectClause
{
get{return_selectClause;}
set{_selectClause=value;}
}
publicstringFromClause
{
get{return_fromClause;}
set{_fromClause=value;}
}
publicStringBuilderWhereClause
{
get{return_whereClause;}
set{_whereClause=value;}
}
publicstringGroupClause
{
get{return_groupClause;}
set{_groupClause=value;}
}
publicstringSortClause
{
get{return_sortClause;}
set{_sortClause=value;}
}
/**////<summary>
///当前页数
///</summary>
publicintPageIndex
{
get{return_pageIndex;}
set{_pageIndex=value;}
}
/**////<summary>
///分页大小
///</summary>
publicintPageSize
{
get{return_pageSize;}
set{_pageSize=value;}
}
/**////<summary>
///生成缓存Key
///</summary>
///<returns></returns>
publicoverridestringGetCacheKey()
{
conststringkeyFormat="Pager-SC:{0}-FC:{1}-WC:{2}-GC:{3}-SC:{4}";
returnstring.Format(keyFormat,SelectClause,FromClause,WhereClause,GroupClause,SortClause);
}
/**////<summary>
///生成查询记录总数的SQL语句
///</summary>
///<returns></returns>
publicstringGenerateCountSql()
{
StringBuildersb=newStringBuilder();
sb.AppendFormat("from{0}",FromClause);
if(WhereClause.Length>0)
sb.AppendFormat("where1=1{0}",WhereClause);
if(!string.IsNullOrEmpty(GroupClause))
sb.AppendFormat("groupby{0}",GroupClause);
returnstring.Format("Selectcount(0){0}",sb);
}
/**////<summary>
///生成分页查询语句,包含记录总数
///</summary>
///<returns></returns>
publicstringGenerateSqlIncludeTotalRecords()
{
StringBuildersb=newStringBuilder();
if(string.IsNullOrEmpty(SelectClause))
SelectClause="*";
if(string.IsNullOrEmpty(SortClause))
SortClause=PK;
intstart_row_num=(PageIndex-1)*PageSize+1;
sb.AppendFormat("from{0}",FromClause);
if(WhereClause.Length>0)
sb.AppendFormat("where1=1{0}",WhereClause);
if(!string.IsNullOrEmpty(GroupClause))
sb.AppendFormat("groupby{0}",GroupClause);
stringcountSql=string.Format("Selectcount(0){0};",sb);
stringtempSql=
string.Format(
"WITHtAS(SELECTROW_NUMBER()OVER(ORDERBY{0})asrow_number,{1}{2})Select*fromtwhererow_numberBETWEEN{3}and{4};",
SortClause,SelectClause,sb,start_row_num,(start_row_num+PageSize-1));
returntempSql+countSql;
}
/**////<summary>
///生成分页查询语句
///</summary>
///<returns></returns>
publicoverridestringGenerateSql()
{
StringBuildersb=newStringBuilder();
if(string.IsNullOrEmpty(SelectClause))
SelectClause="*";
if(string.IsNullOrEmpty(SortClause))
SortClause=PK;
intstart_row_num=(PageIndex-1)*PageSize+1;
sb.AppendFormat("from{0}",FromClause);
if(WhereClause.Length>0)
sb.AppendFormat("where1=1{0}",WhereClause);
if(!string.IsNullOrEmpty(GroupClause))
sb.AppendFormat("groupby{0}",GroupClause);
return
string.Format(
"WITHtAS(SELECTROW_NUMBER()OVER(ORDERBY{0})asrow_number,{1}{2})Select*fromtwhererow_numberBETWEEN{3}and{4}",
SortClause,SelectClause,sb,start_row_num,(start_row_num+PageSize-1));
}
}

使用方法:

复制代码代码如下:

PagerQueryquery=newPagerQuery();
query.PageIndex=1;
query.PageSize=20;
query.PK="ID";
query.SelectClause="*";
query.FromClause="TestTable";
query.SortClause="IDDESC";
if(!string.IsNullOrEmpty(code))
{
query.WhereClause.Append("andID=@ID");
}

a)GenerateCountSql()方法生成的语句为:
Selectcount(0)fromTestTableWhere1=1andID=@ID
b)GenerateSql()方法生成的语句为:
WITHtAS(SELECTROW_NUMBER()OVER(ORDERBYECIDDESC)asrow_number,*fromTestTablewhere1=1andID=@ID)Select*fromtwhererow_numberBETWEEN1and20
c)GenerateSqlIncludetTotalRecords()方法生成的语句为:
WITHtAS(SELECTROW_NUMBER()OVER(ORDERBYE.ECIDDESC)asrow_number,*fromTestTablewhere1=1andID=@ID)Select*fromtwhererow_numberBETWEEN1and20;Selectcount(0)fromECBasicInfowhere1=1andID=@ID;

注意:以上代码生成的SQL语句是曾对SQLSERVER2005以上版本的,希望这些代码对大家有用