[Security - SQL Injection 類別] 較安全的程式碼撰寫方法
前言:
造成資安問題的原因繁多,本篇以紀錄AP端 - SQL Injection 類別為主,請參考OWASP、OWASP Top 10
OWASP Top 10 For 2010:(Injection 問題)
之前看到祭司大的這噗 ~ 反思~大家都說SqlParameter就能全擋掉SQL Injection....
正好公司起了專案,所以自己整理一些資料放上來紀錄,亦不定時更新,以下的示範、寫法、觀念上不足之處,請大家不吝給予指正。
前置介紹與準備:
資料庫:AdventureWorks
檢視表:HumanResources.vEmployee,資料總筆數:290 筆
輸出欄位:City, FirstName, Phone, EmailAddress, AddressLine1
命令:SELECT City, FirstName, Phone, EmailAddress, AddressLine1 FROM HumanResources.vEmployee WHERE City='Seattle' (查出筆數為 44 筆)
以下操作方式;並以 SQL Server Profiler 追縱事件命令 (如何操作 SQL Server Profiler,可參考使用 SQL Server Profiler 追蹤事件)
1. 觸發不安全寫法,傳入City 條件參數:
a. 正常值:Seattle
b. 不正常值:'or'1'='1
2. 觸發較安全寫法,傳入City 條件參數:
a. 正常值:Seattle
b. 不正常值:'or'1'='1
SQL Server Profiler 畫面:
畫面:
ASP.NET前置介紹與準備:
一、.CS 未使用SqlParameter方式進行查詢動作
///<summary>
///未使用SqlParameter方式進行查詢動作
///</summary>
protected void btnUnSecurity_Click(object sender, EventArgs e)
{
DataTable dt = new DataTable();
string sqlStatement = string.Empty;
using (ConnectionString)
{
try
{
ConnectionString.Open();
SqlCommand sqlCommand;
sqlStatement = @"SELECT City,FirstName,Phone,EmailAddress,AddressLine1 FROM HumanResources.vEmployee WHERE City='" + this.txtCity1.Text.Trim() + "'";
sqlCommand = new SqlCommand(sqlStatement, ConnectionString);
SqlDataAdapter adapter = new SqlDataAdapter(sqlCommand);
adapter.Fill(dt);
}
catch
{
this.lblMsg.Text = "無符合的資料!";
this.lblMsg.ForeColor = Color.Red;
}
}
if (dt.Rows.Count > 0)
{
this.lblTotal.Text = dt.Rows.Count.ToString();
this.gvEmployee.DataSource = dt;
this.gvEmployee.DataBind();
}
else
{
this.lblMsg.Text = "無符合的資料!";
this.lblMsg.ForeColor = Color.Red;
this.lblTotal.Text = "0";
this.gvEmployee.DataSource = null;
this.gvEmployee.DataBind();
}
}
畫面結果圖:
a. Web 畫面 - 輸入 參數:Seattle
SQL Server Profiler 畫面:
追蹤紀錄:
實際執行命令:
b. Web 畫面 - 輸入 參數:'or'1'='1
SQL Server Profiler 畫面:
追蹤紀錄:
實際執行命令:
說明:
未使用 SqlParameter 方式,傳入值是 「'or'1'='1」時,條件 or 1=1,恆成立,會導致甚麼資料都可以查詢出,
甚至如果 輸入值為「'or'1'='1; drop table [Table_Name]」,可想而知其嚴重性,故較為不安全。
二、.CS 使用SqlParameter方式進行查詢動作
///<summary>
///使用SqlParameter方式進行查詢動作
///</summary>
protected void btnSecurity_Click(object sender, EventArgs e)
{
DataTable dt = new DataTable();
string sqlStatement = string.Empty;
using (ConnectionString)
{
try
{
ConnectionString.Open();
SqlCommand sqlCommand;
sqlStatement = @"SELECT City,FirstName,Phone,EmailAddress,AddressLine1 FROM HumanResources.vEmployee WHERE City=@City";
sqlCommand = new SqlCommand(sqlStatement, ConnectionString);
sqlCommand.Parameters.AddWithValue("@City",this.txtCity1.Text.Trim());
SqlDataAdapter adapter = new SqlDataAdapter(sqlCommand); adapter.Fill(dt);
}
catch
{
this.lblMsg.Text = "無符合的資料!";
this.lblMsg.ForeColor = Color.Red;
}
}
if (dt.Rows.Count > 0)
{
this.lblTotal.Text = dt.Rows.Count.ToString();
this.gvEmployee.DataSource = dt;
this.gvEmployee.DataBind();
}
else
{
this.lblMsg.Text = "無符合的資料!";
this.lblMsg.ForeColor = Color.Red;
this.lblTotal.Text = "0";
this.gvEmployee.DataSource = null;
this.gvEmployee.DataBind();
}
}
畫面結果圖:
a. Web 畫面 - 輸入 參數:Seattle
SQL Server Profiler 畫面:
追蹤紀錄:
實際執行命令:
說明:
使用 SqlParameter 方式,命令轉換為 Store Procedure 執行處理,傳入值則會以 「字串」 參數給 Where 條件使用。
其中的 nvarchar(7) ,是以輸入的 字串長度 而定。
b. Web 畫面 - 輸入 參數:'or'1'='1
SQL Server Profiler 畫面:
追蹤紀錄:
實際執行命令:
說明:
使用 SqlParameter 方式,命令轉換為 Store Procedure 執行處理,傳入值則會以 「字串」 參數給 Where 條件使用,其中的 nvarchar(9) ,是以輸入的 字串長度 而定。
所以即使傳入值是 「'or'1'='1」,也將其視為 ''or'1'='1' 的字串,故較為安全。
結語說明:
後續亦會逐步更新相關寫法。
以上為的示範,寫法、觀念上不足之處,請大家見諒,也麻煩大家不吝給予指教。
參考資料:
1. 黑暗大的一系列 資安文章 (一定要拜讀的)
2. Will 保哥 的系列 資安文章 (一定要拜讀的)