2015-01-07 60 views
0

嗨我是相當新的MVC和C#我想知道如果我可以使用模型安全防止SQL注入?我創建了一個模型,其中包含我們從客戶端輸入接收到的變量,然後從它們中形成一條SQL語句。我想知道MVC中的內置安全性是否足以防止SQL注入?請看代碼,非常感謝任何建議。MVC 4 SQL字符串注入安全

型號

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 

namespace DataBaseTest.Models 
{ 
    public class BedroomModel 
    { 
    public string YrBlt1 { get; set; } 
    public string YrBlt2 { get; set; } 
    public string TotLivArea1 { get; set; } 
    public string TotLivArea2 { get; set; } 
    public string LotArea1 { get; set; } 
    public string LotArea2 { get; set; } 
    public string Bedrooms { get; set; } 
    public string SalePrice1 { get; set; } 
    public string SalePrice2 { get; set; } 
    public string SaleDate { get; set; } 
    public string AssesVal1 { get; set; } 
    public string AssesVal2 { get; set; } 
    public string Style { get; set; } 
    public string ArchStyle { get; set; } 
    public string TaxUnit { get; set; } 

    // Criteria added during SQL Queries 
    public string YearBuilt { get; set; } 
    public string LivingArea{ get; set; } 
    public string LotArea { get; set; } 
    public string SalePriceA { get; set; } 
    public string SaleDateA { get; set; } 
    public string AssesVal { get; set; } 
    public string StyleA { get; set; } 
    public string ArchStyleA { get; set; } 
    public string ParcelId { get; set; } 
    public string QuickRefId { get; set; } 
    public string TaxunitA { get; set; } 
    public string Address { get; set; } 
    public string ValCode { get; set; } 
    public string BedroomA { get; set; } 

那麼,我們的SQL

[HttpPost] 
    public ActionResult Index(DataBaseTest.Models.BedroomModel user,DataTable dtFindResults) 
    { 
     StringBuilder sbSQL = new StringBuilder(); 
     //// define a list of CustomerModel objects 
     DataSet tempDS = new DataSet(); 

     //string xSQL = "SELECT PropertyAddress,PropertyTypeDesc,PropertyID FROM KDOR_vwPropertyGeneral ORDER BY PropertyAddress"; 
     System.Data.SqlClient.SqlDataAdapter DbCmd = new System.Data.SqlClient.SqlDataAdapter(); 
     string sqlWhereCont = " WHERE "; 
     sbSQL.Append("SELECT "); 
     //sbSQL.Append(SessionHandler.AddressPointsPointsIDColumn + " AS PointsID,"); 
     sbSQL.Append("pg.PropertyNumberSearch,"); 
     sbSQL.Append("pg.QuickRefID,"); 
     sbSQL.Append("pg.PropertyAddress,"); 
     sbSQL.Append("crb.fmsstyle,"); 
     sbSQL.Append("srb.farchstyle,"); 
     sbSQL.Append("pt.TransferValidityCode,"); 
     sbSQL.Append("pg.TaxingUnitGroupCode,"); 
     sbSQL.Append("pt.Price,"); 
     sbSQL.Append("pt.SaleDate,"); 
     sbSQL.Append("crb.fyrblt,"); 
     sbSQL.Append("crb.vResBldgDep_tla_value,"); 
     sbSQL.Append("lm.facres,"); 
     sbSQL.Append("crb.frmbed"); 
     sbSQL.Append(" FROM KDOR_vwPropertyGeneral pg "); 
     sbSQL.Append(" Left Join cama_ResBldg crb ON pg.PropertyID = crb.PropertyID And pg.AdHocTaxYear = crb.AdHocTaxYear "); 
     sbSQL.Append(" Left Join sales_ResBldg srb ON pg.PropertyID = srb.PropertyID"); 
     sbSQL.Append(" Left Join KDOR_vwPropertyTransfer pt On pg.PropertyID = pt.PropertyID"); 
     sbSQL.Append(" Left Join cama_LandMkt lm ON pg.PropertyID = lm.PropertyID And pg.AdHocTaxYear = lm.AdHocTaxYear"); 
     if (!string.IsNullOrEmpty(user.YrBlt1)||!string.IsNullOrEmpty(user.YrBlt2)) 
     { 
      //sbSQL.Append(sqlWhereCont +"PropertyAddress = '" + user.Address + "'"); 
      //sqlWhereCont = "AND "; 
      sbSQL.Append(sqlWhereCont +"crb.fyrblt >="+ user.YrBlt1+ " And crb.fyrblt <= " + user.YrBlt2); 
      sqlWhereCont = "AND "; 
     } 
     if (!string.IsNullOrEmpty(user.TotLivArea1) || !string.IsNullOrEmpty(user.TotLivArea2)) 
     { 
      //sbSQL.Append(sqlWhereCont +"PropertyAddress = '" + user.Address + "'"); 
      //sqlWhereCont = "AND "; 
      sbSQL.Append(sqlWhereCont + "crb.vResBldgDep_tla_value >=" + user.TotLivArea1 + " And crb.vResBldgDep_tla_value <= " + user.TotLivArea2); 
      sqlWhereCont = "AND "; 
     } 
     if (!string.IsNullOrEmpty(user.LotArea1) || !string.IsNullOrEmpty(user.LotArea2)) 
     { 
      //sbSQL.Append(sqlWhereCont +"PropertyAddress = '" + user.Address + "'"); 
      //sqlWhereCont = "AND "; 
      sbSQL.Append(sqlWhereCont + "lm.facres >=" + user.LotArea1 + " And lm.facres <= " + user.LotArea2); 
      sqlWhereCont = "AND "; 
     } 

     if (!string.IsNullOrEmpty(user.Bedrooms)) 
     { 
      sbSQL.Append(sqlWhereCont + "crb.frmbed = '" + user.Bedrooms + "'"); 
      sqlWhereCont = "AND "; 
     } 
     if (!string.IsNullOrEmpty(user.SalePrice1) || !string.IsNullOrEmpty(user.SalePrice2)) 
     { 
      //sbSQL.Append(sqlWhereCont +"PropertyAddress = '" + user.Address + "'"); 
      //sqlWhereCont = "AND "; 
      sbSQL.Append(sqlWhereCont + "pt.Price >=" + user.SalePrice1 + " And pt.Price <= " + user.SalePrice2); 
      sqlWhereCont = "AND "; 
     } 
     if (!string.IsNullOrEmpty(user.SaleDate)) 
     { 
      sbSQL.Append(sqlWhereCont + "pt.SaleDate = '" + user.SaleDate + "'"); 
      sqlWhereCont = "AND "; 
     } 
     if (!string.IsNullOrEmpty(user.AssesVal1) || !string.IsNullOrEmpty(user.AssesVal2)) 
     { 
      //sbSQL.Append(sqlWhereCont +"PropertyAddress = '" + user.Address + "'"); 
      //sqlWhereCont = "AND "; 
      sbSQL.Append(sqlWhereCont + "crb.vResBldgDep_tla_value >=" + user.AssesVal1 + " And crb.vResBldgDep_tla_value <= " + user.AssesVal2); 
      sqlWhereCont = "AND "; 
     } 
     if (!string.IsNullOrEmpty(user.Style)) 
     { 
      sbSQL.Append(sqlWhereCont + "crb.fmsstyle = '" + user.Style + "'"); 
      sqlWhereCont = "AND "; 
     } 
     if (!string.IsNullOrEmpty(user.ArchStyle)) 
     { 
      sbSQL.Append(sqlWhereCont + "srb.farchstyle = '" + user.ArchStyle + "'"); 
      sqlWhereCont = "AND "; 
     } 
     if (!string.IsNullOrEmpty(user.TaxUnit)) 
     { 
      sbSQL.Append(sqlWhereCont + "pg.TaxingUnitGroupCode = '" + user.TaxUnit + "'"); 
      sqlWhereCont = "AND "; 
     } 
     sbSQL.Append(" ORDER BY "); 
     sbSQL.Append(" pg.QuickRefID "); 


     //// populate a list of CustomerModel objects from database 
     string MyConnectionString = ConfigurationManager.ConnectionStrings["WLConnection"].ConnectionString; 
     System.Data.SqlClient.SqlConnection cnn = new System.Data.SqlClient.SqlConnection(MyConnectionString); 
     System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(sbSQL.ToString(), cnn); 
     cmd.CommandTimeout = 30000; 
     DbCmd.SelectCommand = cmd; 
     DbCmd.Fill(tempDS, "ResultSet"); 
     DataTable resultSet = tempDS.Tables["ResultSet"]; 
     var vm = new List<BedroomModel>(); 
     foreach (DataRow dr in tempDS.Tables[0].Rows) 
     { 
      vm.Add(new BedroomModel 
      { 
       BedroomA = dr.ItemArray[12].ToString(), 
       YearBuilt = dr.ItemArray[9].ToString(), 
       LivingArea = dr.ItemArray[7].ToString(), 
       LotArea = dr.ItemArray[3].ToString(), 
       SaleDateA = dr.ItemArray[8].ToString(), 
       SalePriceA = dr.ItemArray[10].ToString(), 
       AssesVal = dr.ItemArray[5].ToString(), 
       StyleA = dr.ItemArray[3].ToString(), 
       ArchStyleA = dr.ItemArray[4].ToString(), 
       ParcelId = dr.ItemArray[0].ToString(), 
       QuickRefId = dr.ItemArray[1].ToString(), 
       TaxunitA = dr.ItemArray[6].ToString(), 
       Address = dr.ItemArray[2].ToString(), 
       ValCode = dr.ItemArray[5].ToString(), 


      }); 
      } 
     //DbCmd.Fill(dtFindResults); 
     //var x = dtFindResults.Rows.Count; 
     cnn.Close(); 
     return View("Result",vm); 
     //// return the list of CustomerModel objects to our View 
     //return View("Result", resultSet); 
     //return View(ViewBag.data); 
    } 
+5

總之,* no *。使用參數化查詢。總是。您可以基於用戶輸入動態地構建查詢本身,但來自用戶的值應始終作爲參數傳遞,而不是直接連接到查詢中。 –

+3

您正在根據用戶輸入即時創建SQL字符串。這是* not *防範SQL注入的事實例子。 –

+0

如何建立動態和安全的建議? @PrestonGuillot –

回答

5

參數化查詢是必須的。但是,這並不妨礙您能夠構建動態查詢,您只需要以不同的方式處理它。

根據用戶輸入做出決定很好;它的不是罰款將這些值連接到一個查詢。

一個簡單的例子:

using(IDbCommand cmd = GetCommand()) 
{ 
    string lotSize = "12345"; 
    bool includeLotSize = !string.IsNullOrWhiteSpace(lotSize); 

    var sb = new StringBuilder(); 
    sb.AppendLine("SELECT Col1, Col2 FROM dbo.Foo"); 

    // you might also vary the columns returned based on what the user asked for 

    if(includeLotSize) 
    { 
     sb.AppendLine("WHERE LotSize = @LotSize"); 

     // The query will expect the lot size, so add a parameter here to pass 
     // the lot size value. 
     cmd.Parameters.Add(new SqlParameter("LotSize", lotSize)); 
    } 
} 

請注意,您的許多字符串屬性的樣子,他們可能是一個更具體的類型(整型,浮點,一個int指向數據庫查詢等)。這不會阻止SQL注入,但它可以用於驗證(以及使視圖模型更清晰)。

另請注意,在.Net中有很多不同的方法可以連接到數據庫,但請確保您正確處理資源(請注意我已添加的using聲明)。

+0

謝謝蒂姆,這是我第一次在網上工作,我不認爲我們會受到攻擊,但我不想冒險,我仍然可以使用模型輸入sql嗎?像字符串lotsize = user.lotsize; –

+1

您可以繼續使用該模型來收集用戶輸入。重點是隻將用戶輸入作爲參數傳遞給數據庫,而不是原始字符串。你應該可以在我的答案中使用這個模式來代替'sbSQL.Append(sqlWhereCont +「crb.fyrblt> =」+ user.YrBlt1 +「和crb.fyrblt <=」+ user.YrBlt2);' –

+0

Tim如果我使用方法內的字符串,wouldnt仍然允許sql注入,因爲我仍然會得到用戶輸入? @Tim Medora –