最近公司的程式有被掃到「Data Filter Injection attack」的問題,
是什麼造成「Data Filter Injection attack」的問題呢?
又該如何解決呢?
最近公司的程式有被掃到「Data Filter Injection attack」的問題,程式大約如下,
1.Get時先將資料從DB中取出來,然後放在ViewState之中
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack ){
DataTable dt = new DataTable("myDT");
dt.Columns.Add("c1", typeof(string));
for(int i=0;i<5;i++){
dt.Rows.Add(i.ToString());
}
ViewState["myDT"] = dt;
}
}
2.在需要的時候,再依QueryString中的值來Filter!
DataTable dt = ViewState["myDT"] as DataTable;
if (dt != null)
{
string filter = string.Format("c1 = '{0}'"
, Server.HtmlEncode(Request.QueryString["id"]));
var drs = dt.Select(filter);
foreach(DataRow dr in drs){
Response.Write(dr["c1"]);
}
}
以上的程式有幾個問題
1.將DataTable放在ViewState之中,每次Postback都會在Client及Server傳遞,造成效能的影響。
2.ViewState有可能會被Client竄改。
3.DataTable的Select Filter沒有經過處理,會有Injection的問題。
而第2、3點就是會有「Data Filter Injection attack」的問題。
針對以上的問題,可以用以下的方式來解決。
1.使用ASP.NET WebForms 常常被人說ViewState過大,所以可以在BasePage中將原本存在Hidden欄位(HiddenFieldPageStatePersister),改放到Session(SessionPageStatePersister)之中。
public class MyPageAdapter : System.Web.UI.Adapters.PageAdapter {
public override PageStatePersister GetStatePersister() {
return new SessionPageStatePersister(Page);
}
}
2.資料可以在使用到時,再到DB中取得,並透過參數方式查詢。或是將它存到Cache或Session之中。
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack ){
DataTable dt = new DataTable("myDT");
dt.Columns.Add("c1", typeof(string));
for(int i=0;i<5;i++){
dt.Rows.Add(i.ToString());
}
Cache[string.Format("{0}-myDT", Session.SessionID)] = dt;
}
}
3.1.DataTable的Select Filter要處理(請針對資料型態來處理或判斷資料型別),以避免Injection的問題。
DataTable dt2 = Cache[string.Format("{0}-myDT", Session.SessionID)] as DataTable;
if (dt2 != null)
{
string filterValue = Server.HtmlEncode(Request.QueryString["id"]);
if(!string.IsNullOrEmpty(filterValue)){
string filter = string.Format("c1 = '{0}'", filterValue.Replace("'", "''"));
var drs = dt2.Select(filter);
foreach (DataRow dr in drs)
{
Response.Write(dr["c1"]);
}
}
}
3.2.或是改用Linq方式來查詢(要加入System.Data.DataSetExtensions參考),如下,
DataTable dt2 = Cache[string.Format("{0}-myDT", Session.SessionID)] as DataTable;
if (dt2 != null)
{
string filterValue = Server.HtmlEncode(Request.QueryString["id"]);
if(!string.IsNullOrEmpty(filterValue)){
var drs2 = dt2.AsEnumerable()
.Where(r => r.Field<string>("c1")
.Equals(filterValue, StringComparison.InvariantCultureIgnoreCase)).Select(r=>r);
foreach (DataRow dr in drs2)
{
Response.Write(dr["c1"]);
}
}
}
參考資料
DataTableExtensions.AsEnumerable
如果大家有其他的方式,請分享給大家知道,謝謝大家!
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^