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

 更新时间:2010年07月11日 13:00:22   作者:  
前些时间看了玉开兄的“如此高效通用的分页存储过程是带有sql注入漏洞的”这篇文章,才突然想起某个项目也是使用了累似的通用分页存储过程。
使用这种通用的存储过程进行分页查询,想要防SQL注入,只能对输入的参数进行过滤,例如将一个单引号“'”转换成两个单引号“''”,但这种做法是不安全的,厉害的黑客可以通过编码的方式绕过单引号的过滤,要想有效防SQL注入,只有参数化查询才是最终的解决方案。但问题就出在这种通用分页存储过程是在存储过程内部进行SQL语句拼接,根本无法修改为参数化的查询语句,因此这种通用分页存储过程是不可取的。但是如果不用通用的分页存储过程,则意味着必须为每个具体的分页查询写一个分页存储过程,这会增加不少的工作量。
经过几天的时间考虑之后,想到了一个用代码来生成参数化的通用分页查询语句的解决方案。代码如下:
复制代码 代码如下:

public class PagerQuery
{
private int _pageIndex;
private int _pageSize = 20;
private string _pk;
private string _fromClause;
private string _groupClause;
private string _selectClause;
private string _sortClause;
private StringBuilder _whereClause;
public DateTime DateFilter = DateTime.MinValue;
protected QueryBase()
{
_whereClause = new StringBuilder();
}
/**//// <summary>
/// 主键
/// </summary>
public string PK
{
get { return _pk; }
set { _pk = value; }
}
public string SelectClause
{
get { return _selectClause; }
set { _selectClause = value; }
}
public string FromClause
{
get { return _fromClause; }
set { _fromClause = value; }
}
public StringBuilder WhereClause
{
get { return _whereClause; }
set { _whereClause = value; }
}
public string GroupClause
{
get { return _groupClause; }
set { _groupClause = value; }
}
public string SortClause
{
get { return _sortClause; }
set { _sortClause = value; }
}
/**//// <summary>
/// 当前页数
/// </summary>
public int PageIndex
{
get { return _pageIndex; }
set { _pageIndex = value; }
}
/**//// <summary>
/// 分页大小
/// </summary>
public int PageSize
{
get { return _pageSize; }
set { _pageSize = value; }
}
/**//// <summary>
/// 生成缓存Key
/// </summary>
/// <returns></returns>
public override string GetCacheKey()
{
const string keyFormat = "Pager-SC:{0}-FC:{1}-WC:{2}-GC:{3}-SC:{4}";
return string.Format(keyFormat, SelectClause, FromClause, WhereClause, GroupClause, SortClause);
}
/**//// <summary>
/// 生成查询记录总数的SQL语句
/// </summary>
/// <returns></returns>
public string GenerateCountSql()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat(" from {0}", FromClause);
if (WhereClause.Length > 0)
sb.AppendFormat(" where 1=1 {0}", WhereClause);
if (!string.IsNullOrEmpty(GroupClause))
sb.AppendFormat(" group by {0}", GroupClause);
return string.Format("Select count(0) {0}", sb);
}
/**//// <summary>
/// 生成分页查询语句,包含记录总数
/// </summary>
/// <returns></returns>
public string GenerateSqlIncludeTotalRecords()
{
StringBuilder sb = new StringBuilder();
if (string.IsNullOrEmpty(SelectClause))
SelectClause = "*";
if (string.IsNullOrEmpty(SortClause))
SortClause = PK;
int start_row_num = (PageIndex - 1)*PageSize + 1;
sb.AppendFormat(" from {0}", FromClause);
if (WhereClause.Length > 0)
sb.AppendFormat(" where 1=1 {0}", WhereClause);
if (!string.IsNullOrEmpty(GroupClause))
sb.AppendFormat(" group by {0}", GroupClause);
string countSql = string.Format("Select count(0) {0};", sb);
string tempSql =
string.Format(
"WITH t AS (SELECT ROW_NUMBER() OVER(ORDER BY {0}) as row_number,{1}{2}) Select * from t where row_number BETWEEN {3} and {4};",
SortClause, SelectClause, sb, start_row_num, (start_row_num + PageSize - 1));
return tempSql + countSql;
}
/**//// <summary>
/// 生成分页查询语句
/// </summary>
/// <returns></returns>
public override string GenerateSql()
{
StringBuilder sb = new StringBuilder();
if (string.IsNullOrEmpty(SelectClause))
SelectClause = "*";
if (string.IsNullOrEmpty(SortClause))
SortClause = PK;
int start_row_num = (PageIndex - 1)*PageSize + 1;
sb.AppendFormat(" from {0}", FromClause);
if (WhereClause.Length > 0)
sb.AppendFormat(" where 1=1 {0}", WhereClause);
if (!string.IsNullOrEmpty(GroupClause))
sb.AppendFormat(" group by {0}", GroupClause);
return
string.Format(
"WITH t AS (SELECT ROW_NUMBER() OVER(ORDER BY {0}) as row_number,{1}{2}) Select * from t where row_number BETWEEN {3} and {4}",
SortClause, SelectClause, sb, start_row_num, (start_row_num + PageSize - 1));
}
}

使用方法:

复制代码 代码如下:

PagerQuery query = new PagerQuery();
query.PageIndex = 1;
query.PageSize = 20;
query.PK = "ID";
query.SelectClause = "*";
query.FromClause = "TestTable";
query.SortClause = "ID DESC";
if (!string.IsNullOrEmpty(code))
{
query.WhereClause.Append(" and ID= @ID");
}

a) GenerateCountSql ()方法生成的语句为:
Select count(0) from TestTable Where 1=1 and ID= @ID
b) GenerateSql()方法生成的语句为:
WITH t AS (SELECT ROW_NUMBER() OVER(ORDER BY ECID DESC) as row_number, * from TestTable where 1=1 and ID= @ID) Select * from t where row_number BETWEEN 1 and 20
c) GenerateSqlIncludetTotalRecords()方法生成的语句为:
WITH t AS (SELECT ROW_NUMBER() OVER(ORDER BY E.ECID DESC) as row_number,* from TestTable where 1=1 and ID= @ID) Select * from t where row_number BETWEEN 1 and 20;Select count(0) from ECBasicInfo where 1=1 and ID= @ID;

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

相关文章

  • 注册页实现激活邮箱验证(asp.net c#)

    注册页实现激活邮箱验证(asp.net c#)

    在填写注册提交后,大一点的网站会有邮箱激活验证这一步,本文也是实现了一下,感兴趣的朋友可以参考下哈,希望可以帮助到你
    2013-04-04
  • asp.net URL 显示乱码 解决方法

    asp.net URL 显示乱码 解决方法

    刚刚接触网页开发,不过遇到URR参数传递错误的问题,两个页面进行信息交互时可以用url进行传递,但是如果传递信息的编码格式不是UTF-8(或者不是设置的默认格式)URL传递时会出现乱码。
    2009-06-06
  • 在ASP.NET Core中用HttpClient发送POST, PUT和DELETE请求

    在ASP.NET Core中用HttpClient发送POST, PUT和DELETE请求

    这篇文章主要介绍了在ASP.NET Core中用HttpClient发送POST, PUT和DELETE请求的方法,帮助大家更好的理解和学习使用ASP.NET Core,感兴趣的朋友可以了解下
    2021-03-03
  • asp.net动态生成HTML表单的方法

    asp.net动态生成HTML表单的方法

    这篇文章主要介绍了asp.net动态生成HTML表单的方法,结合实例形式分析了asp.net动态生成HTML表单的相关控件使用技巧与注意事项,需要的朋友可以参考下
    2017-03-03
  • 在ASP.Net Core中使用Lamar的全过程

    在ASP.Net Core中使用Lamar的全过程

    这篇文章主要给大家介绍了关于在ASP.Net Core中使用Lamar的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • .NET中弹性和瞬时处理库Polly的使用详解

    .NET中弹性和瞬时处理库Polly的使用详解

    Polly 是一个 .NET 弹性和瞬态故障处理库,允许开发人员以 Fluent 和线程安全的方式来实现重试、断路、超时、隔离和回退策略,下面就跟随小编一起来看看它的具体使用吧
    2024-01-01
  • 运行page页面时的事件执行顺序及页面的回发与否深度了解

    运行page页面时的事件执行顺序及页面的回发与否深度了解

    page页面时的事件执行顺序的了解对于一些.net开发者起到者尤关重要的作用;页面的回发与否会涉及到某些事件执行与不执行,在本文中会详细介绍,感兴趣的朋友可以了解下
    2013-01-01
  • ASP.NET框架中的数据绑定概要与数据绑定表达式的使用

    ASP.NET框架中的数据绑定概要与数据绑定表达式的使用

    数据绑定是ASP.NET中操作数据的基础方式,这里我们暂时抛开.NET提供的控件,来从基础上讲解ASP.NET框架中的数据绑定概要与数据绑定表达式的使用:
    2016-06-06
  • ASP.NET MVC5验证系列之Remote Validation

    ASP.NET MVC5验证系列之Remote Validation

    这篇文章主要为大家详细介绍了ASP.NET MVC5验证系列之Remote Validation,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • LINQ教程之LINQ简介

    LINQ教程之LINQ简介

    这篇文章介绍了语言集成查询LINQ,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03

最新评论