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

前些时间看了玉开兄的“如此高效通用的分页存储过程是带有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));
    }
  }

时间: 2025-01-02 11:22:11

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

在Global.asax文件里实现通用防SQL注入漏洞程序(适应于post/get请求)_实用技巧

首先,创建一个SQLInjectionHelper类完成恶意代码的检查 代码如下: 复制代码 代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Text.RegularExpressions; /// <summary> ///SQLInjectionHelper 的摘要说明 /// </summary> public cla

php mysql_real_escape_string防sql注入详解

mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符.下列字符受影响:  代码如下 复制代码 x00 n r ' " x1a 如果成功,则该函数返回被转义的字符串.如果失败,则返回 false. 易利用下面的这个函数,就可以有效过滤了.  代码如下 复制代码 function safe($s){ //安全过滤函数 if(get_magic_quotes_gpc()){ $s=stripslashes($s); } $s=mysql_real_es

discuz防SQL注入程序代码

discuz 是一套通用的 PHP 社区论坛软件系统,在国内占有大量的用户群体,是做论坛的首选系统,在很早的时候就用 discuz 做论坛系统,感触最深的应该就是论坛的安全问题了,以前使用的时候,经常会有大量的信息进行注入,真是防不胜防. 好在 discuz 系统的更新很迅速,每一次的安全问题很快就得到了更新,而最头疼的问题恐怕就是 sql 的注入了,其实不只 discuz 系统,互联网上进行网络攻击的 SQL 注入是很可怕的,虽然 discuz 系统现有的安全问题已经非常完善了,但因为系统功能

php mysql_real_escape_string addslashes及mysql绑定参数防SQL注入攻击

php mysql_real_escape_string addslashes及mysql绑定参数防SQL注入攻击 php防止SQL注入攻击一般有三种方法: 使用mysql_real_escape_string函数 使用addslashes函数 使用mysql bind_param() 本文章向大家详细介绍这三个方法在防止SQL注入攻击中的效果及区别. mysql_real_escape_string防sql注入攻击 mysql_real_escape_string() 函数转义 SQL 语句中

EasyASP v2.2新功能介绍(1):Easp是如何实现防sql注入的

EasyASP终于到v2.2了,目前还在完善手册,群里有很多人问如何使用的问题 ,所以打算在写手册的同时写一些新功能的介绍,方便使用Easp 的童鞋们快速 进入状态.说实话,看到这么多人还在写ASP.还在支持Easp,觉得蛮难得的, 所以也一直没有丢下Easp的开发,还是希望Easp能给最后的ASPer们一点微薄的 帮助. EasyASP v2.2的改动比较大,放弃了不少原来我觉得不好用的方法,当然, 更多的是加入了不少我觉得会用得很哈屁的新功能.这是这个系列的第一篇文章 ,准备讲讲EasyAS

PHP用PDO防Sql注入注意事项

在PHP 5.3.6及以前版本中,并不支持在DSN中的charset定义,而应该使用PDO::MYSQL_ATTR_INIT_COMMAND设置初始SQL, 即我们常用的 set names gbk指令. 为何PDO能防SQL注入? 请先看以下PHP代码:  代码如下 复制代码 <?php $pdo = new PDO("mysql:host=192.168.0.1;dbname=test;charset=utf8","root"); $st = $pdo-&

Black Hat|长亭科技:防SQL注入利器-SQLChop

本文讲的是 Black Hat|长亭科技:防SQL注入利器-SQLChop,当程序过分信任用户的输入,直接将用户的输入与后台的SQL语句拼接在一起并执行时,如果用户输入带有恶意,SQL注入就发生了. 美国当地时间8月5日,国内安全新兴企业长亭科技在黑帽大会的军火库分会场(Arsenal),现场为来自全球各地的安全从业人员进行技术讲解,并演示他们的"无规则SQL注入攻击检测与防御引擎". 结合统计资料和实际情况来看,SQL注入仍然占据互联网威胁安全事件中非常大的比例(接近1/3)而且并没

asp.net防sql注入多种方法与实例代码应用(1/4)

asp教程.net防sql注入多种方法与实例代码应用 清除Request方法的注入问题         static string[] get_sql_a()         {             string Sql_1 = "exec|insert+|select+|delete|update|count|master+|truncate|char|declare|drop+|drop+table|creat+|creat+table";             string

asp防sql注入源程序

<% squery=lcase(Request.ServerVariables("QUERY_STRING")) sURL=lcase(Request.ServerVariables("HTTP_HOST")) SQL_injdata =":|;|>|<|--|sp_|xp_||dir|cmd|^|(|)|+|$|'|copy|format|and|exec|insert|select|delete|update|count|*|chr|