SQL 주입 방지 매개 변수화된 일반 페이지 조회문 생성

6360 단어
이런 통용적인 저장 프로세스를 사용하여 페이지 조회를 하는데 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();
}
/**////
///
///

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; }
}
/**////
///
///

public int PageIndex
{
get { return _pageIndex; }
set { _pageIndex = value; }
}
/**////
///
///

public int PageSize
{
get { return _pageSize; }
set { _pageSize = value; }
}
/**////
/// Key
///

///
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);
}
/**////
/// SQL
///

///
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);
}
/**////
/// ,
///

///
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;
}
/**////
///
///

///
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 이상 버전에 대한 것입니다. 이 코드가 여러분에게 유용하길 바랍니다.

좋은 웹페이지 즐겨찾기