防SQL注入 生成參數(shù)化的通用分頁(yè)查詢(xún)語(yǔ)句
更新時(shí)間:2010年07月11日 13:00:22 作者:
前些時(shí)間看了玉開(kāi)兄的“如此高效通用的分頁(yè)存儲(chǔ)過(guò)程是帶有sql注入漏洞的”這篇文章,才突然想起某個(gè)項(xiàng)目也是使用了累似的通用分頁(yè)存儲(chǔ)過(guò)程。
使用這種通用的存儲(chǔ)過(guò)程進(jìn)行分頁(yè)查詢(xún),想要防SQL注入,只能對(duì)輸入的參數(shù)進(jìn)行過(guò)濾,例如將一個(gè)單引號(hào)“'”轉(zhuǎn)換成兩個(gè)單引號(hào)“''”,但這種做法是不安全的,厲害的黑客可以通過(guò)編碼的方式繞過(guò)單引號(hào)的過(guò)濾,要想有效防SQL注入,只有參數(shù)化查詢(xún)才是最終的解決方案。但問(wèn)題就出在這種通用分頁(yè)存儲(chǔ)過(guò)程是在存儲(chǔ)過(guò)程內(nèi)部進(jìn)行SQL語(yǔ)句拼接,根本無(wú)法修改為參數(shù)化的查詢(xún)語(yǔ)句,因此這種通用分頁(yè)存儲(chǔ)過(guò)程是不可取的。但是如果不用通用的分頁(yè)存儲(chǔ)過(guò)程,則意味著必須為每個(gè)具體的分頁(yè)查詢(xún)寫(xiě)一個(gè)分頁(yè)存儲(chǔ)過(guò)程,這會(huì)增加不少的工作量。
經(jīng)過(guò)幾天的時(shí)間考慮之后,想到了一個(gè)用代碼來(lái)生成參數(shù)化的通用分頁(yè)查詢(xún)語(yǔ)句的解決方案。代碼如下:
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>
/// 當(dāng)前頁(yè)數(shù)
/// </summary>
public int PageIndex
{
get { return _pageIndex; }
set { _pageIndex = value; }
}
/**//// <summary>
/// 分頁(yè)大小
/// </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>
/// 生成查詢(xún)記錄總數(shù)的SQL語(yǔ)句
/// </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>
/// 生成分頁(yè)查詢(xún)語(yǔ)句,包含記錄總數(shù)
/// </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>
/// 生成分頁(yè)查詢(xún)語(yǔ)句
/// </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 ()方法生成的語(yǔ)句為:
Select count(0) from TestTable Where 1=1 and ID= @ID
b) GenerateSql()方法生成的語(yǔ)句為:
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()方法生成的語(yǔ)句為:
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語(yǔ)句是曾對(duì)SQL SERVER 2005以上版本的,希望這些代碼對(duì)大家有用
經(jīng)過(guò)幾天的時(shí)間考慮之后,想到了一個(gè)用代碼來(lái)生成參數(shù)化的通用分頁(yè)查詢(xún)語(yǔ)句的解決方案。代碼如下:
復(fù)制代碼 代碼如下:
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>
/// 當(dāng)前頁(yè)數(shù)
/// </summary>
public int PageIndex
{
get { return _pageIndex; }
set { _pageIndex = value; }
}
/**//// <summary>
/// 分頁(yè)大小
/// </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>
/// 生成查詢(xún)記錄總數(shù)的SQL語(yǔ)句
/// </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>
/// 生成分頁(yè)查詢(xún)語(yǔ)句,包含記錄總數(shù)
/// </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>
/// 生成分頁(yè)查詢(xún)語(yǔ)句
/// </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));
}
}
使用方法:
復(fù)制代碼 代碼如下:
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 ()方法生成的語(yǔ)句為:
Select count(0) from TestTable Where 1=1 and ID= @ID
b) GenerateSql()方法生成的語(yǔ)句為:
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()方法生成的語(yǔ)句為:
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語(yǔ)句是曾對(duì)SQL SERVER 2005以上版本的,希望這些代碼對(duì)大家有用
您可能感興趣的文章:
- Oracle、MySQL和SqlServe三種數(shù)據(jù)庫(kù)分頁(yè)查詢(xún)語(yǔ)句的區(qū)別介紹
- SQLSERVER分頁(yè)查詢(xún)關(guān)于使用Top方式和row_number()解析函數(shù)的不同
- mysql、mssql及oracle分頁(yè)查詢(xún)方法詳解
- Oracle實(shí)現(xiàn)分頁(yè)查詢(xún)的SQL語(yǔ)法匯總
- SQL Server 分頁(yè)查詢(xún)通用存儲(chǔ)過(guò)程(只做分頁(yè)查詢(xún)用)
- sqlserver2005利用臨時(shí)表和@@RowCount提高分頁(yè)查詢(xún)存儲(chǔ)過(guò)程性能示例分享
- mysql分頁(yè)原理和高效率的mysql分頁(yè)查詢(xún)語(yǔ)句
- Mysql中分頁(yè)查詢(xún)的兩個(gè)解決方法比較
- 高效的SQLSERVER分頁(yè)查詢(xún)(推薦)
- oracle,mysql,SqlServer三種數(shù)據(jù)庫(kù)的分頁(yè)查詢(xún)的實(shí)例
- SQL分頁(yè)查詢(xún)方式匯總
相關(guān)文章
ASP.NET怎么操作DataTable實(shí)例應(yīng)用
有機(jī)會(huì)在博客園的博問(wèn)頻道上看到一個(gè)問(wèn)題,《ASP.NET怎么操作DataTable》;需要的朋友可以參考下2012-11-11
asp.net+js實(shí)現(xiàn)的ajax sugguest搜索提示效果
阿會(huì)楠根據(jù)網(wǎng)上一份原作者不詳?shù)拇a進(jìn)行了修改,以適合自己的項(xiàng)目并增加了多個(gè)功能。此次放出的代碼為基本實(shí)現(xiàn)代碼,也是最接近原來(lái)的代碼,略去其他功能。版權(quán)歸原作者所有。2009-04-04
.net core項(xiàng)目中常用的幾款類(lèi)庫(kù)詳解(值得收藏)
這篇文章主要給大家介紹了關(guān)于.net core項(xiàng)目中常用的幾款類(lèi)庫(kù)的相關(guān)資料,文章通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用.net core具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04
ASP.NET中配合JS實(shí)現(xiàn)頁(yè)面計(jì)時(shí)(定時(shí))自動(dòng)跳轉(zhuǎn)
這篇文章主要介紹了ASP.NET中配合JS實(shí)現(xiàn)頁(yè)面計(jì)時(shí)(定時(shí))自動(dòng)跳轉(zhuǎn),本文主要依靠JS實(shí)現(xiàn)需求,只是在ASP.NET中實(shí)現(xiàn)而已,需要的朋友可以參考下2015-06-06
將選擇的圖片顯示在listview中,并顯示filename,path和type的簡(jiǎn)單實(shí)例
這篇文章介紹了將選擇的圖片顯示在listview中,并顯示filename,path和type的簡(jiǎn)單實(shí)例,有需要的朋友可以參考一下2013-10-10
.net重啟iis線程池和iis站點(diǎn)程序代碼分享
服務(wù)器監(jiān)控,一定時(shí)間內(nèi)或者iis異常就需要重啟線程池和站點(diǎn),下面我們用代碼來(lái)做這個(gè)功能2013-12-12

