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

2016-02-19 18:18 22 1 收藏

下面图老师小编跟大家分享防SQL注入:生成参数化的通用分页查询语句,一起来学习下过程究竟如何进行吧!喜欢就赶紧收藏起来哦~

【 tulaoshi.com - 编程语言 】

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

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  经过几天的时间考虑之后,想到了一个用代码来生成参数化的通用分页查询语句的解决方案。代码如下:

  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

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  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以上版本的,希望这些代码对大家有用

来源:https://www.tulaoshi.com/n/20160219/1617230.html

延伸阅读
标签: Web开发
下面我们将要介绍另一种在ASP里防SQL注入攻击的方法,该方法不仅仅在ASP里适用,实际上可以在任何使用ADO对象模型与数据库交互的语言中,准确的说称之为基于ADO对象模型的防SQL注入的方法或许更恰当些。好了废话不说了,来看看代码 代码如下: Dim conn,cmd,pra set conn=server.createobject("adodb.connection") conn.Open "…………" '这...
标签: SQLServer
在Access中进行时间的比较sql语句很简单,如Select * From table Where thetime#"& Now() &"#这样即可     在MSSQL就不能这样,要用DateDiff语句和GetDate()函数进行比较。     如Select Count(*) From table Where DateDiff(s,GetDate(),thetime)0,我自己特别做了个50万条数据的的表,执...
具体操作: 根据master.dbo.sysprocesses中的spid和blocked查找当前阻塞语句的主人,然后使用DBCC INPUTBUFFER ()查看阻塞语句。 例子: 打开三个查询分析器 A、B、C 创建一个测试用的表 testDia Create Table testDia(ID int); 在A执行以下语句: Begin tran Insert Into testDia Values(1); 在B执行以下语句: Select * from t...
标签: ASP
  SQL注入被那些菜鸟级别的所谓黑客高手玩出了滋味,发现现在大部分黑客入侵都是基于SQL注入实现的,哎,谁让这个入门容易呢,好了,不说废话了,现在我开始说如果编写通用的SQL防注入程序一般的http请求不外乎get 和 post,所以只要我们在文件中过滤所有post或者get请求中的参数信息中非法字符即可,所以我们实现http 请求信息过滤就...
今天看了两篇关于存储过程SQL注入漏洞的文章: 1):如此高效通用的分页存储过程是带有sql注入漏洞的 2):防SQL注入:生成参数化的通用分页查询语句 怎么看怎么觉的别扭,在我印象中存储过程是不会存在注入漏洞的啊?起码我目前的水平还不了解如何注入存储过程。如果大家有注入的方法请指教。换句话说存储过程本身并无注入漏洞...

经验教程

195

收藏

12
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部