防SQL注入:生成參數化的通用分頁查詢語句
系統
2019-08-12 01:53:06
1658 0
原文:
防SQL注入:生成參數化的通用分頁查詢語句
????? 前些時間看了玉開兄的“
如此高效通用的分頁存儲過程是帶有sql注入漏洞的
”這篇文章,才突然想起某個項目也是使用了累似的通用分頁存儲過程。使用這種通用的存儲過程進行分頁查詢,想要防SQL注入,只能對輸入的參數進行過濾,例如將一個單引號“'”轉換成兩個單引號“''”,但這種做法是不安全的,厲害的黑客可以通過編碼的方式繞過單引號的過濾,要想有效防SQL注入,只有參數化查詢才是最終的解決方案。但問題就出在這種通用分頁存儲過程是在存儲過程內部進行SQL語句拼接,根本無法修改為參數化的查詢語句,因此這種通用分頁存儲過程是不可取的。但是如果不用通用的分頁存儲過程,則意味著必須為每個具體的分頁查詢寫一個分頁存儲過程,這會增加不少的工作量。
????? 經過幾天的時間考慮之后,想到了一個用代碼來生成參數化的通用分頁查詢語句的解決方案。代碼如下:
Code
????
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以上版本的,希望這些代碼對大家有用
防SQL注入:生成參數化的通用分頁查詢語句
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】 元
喜歡作者