【问题标题】:MVC 4 SQL string injection SecurityMVC 4 SQL 字符串注入安全性
【发布时间】:2015-01-07 21:53:07
【问题描述】:

您好,我对 MVc 和 C# 还很陌生,我想知道是否可以使用模型安全性来防止 SQL 注入?我创建了一个模型,其中包含我们从客户端输入接收的变量,然后从中形成 SQL 语句。我想知道 MVC 中的内置安全性是否足以防止 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);
    }

【问题讨论】:

  • 一句话,没有。使用参数化查询。总是。您可以根据用户输入动态构建查询本身,但来自用户的值应始终作为参数传递,而不是直接连接到查询中。
  • 您正在根据用户输入动态构建 SQL 字符串。这是如何防范 SQL 注入的事实示例。
  • 关于如何动态和安全地构建它的任何建议? @PrestonGuillot
  • 使用参数化查询。

标签: c# sql-server asp.net-mvc asp.net-mvc-4


【解决方案1】:

参数化查询是必须的。但是,这并不妨碍您构建动态查询,您只需要以不同的方式处理它。

可以根据用户输入做出决定; 将这些值连接到查询中。

一个简单的例子:

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、float、指向数据库查找的 int 等)。这不会阻止 SQL 注入,但它可以用于验证(以及使您的视图模型更清晰)。

另请注意,在 .Net 中连接到数据库的方法有很多种,但请确保正确处理资源(注意我添加的 using 语句)。

【讨论】:

  • 谢谢蒂姆,这是我第一次在网上锻炼,我认为我们不会受到攻击,但我不想冒险,我仍然可以使用模型输入sql吗?像字符串lotsize = user.lotsize;
  • 您可以继续使用模型来收集用户输入。关键是只将用户输入作为参数传递给数据库,而不是作为原始字符串。您应该可以在我的答案中使用该模式来替换 sbSQL.Append(sqlWhereCont +"crb.fyrblt &gt;="+ user.YrBlt1+ " And crb.fyrblt &lt;= " + user.YrBlt2 ); 之类的代码
  • Tim 如果我在方法中使用 a 字符串,那是否仍然允许 sql 注入,因为我仍然可以获得用户输入? @蒂姆梅多拉
  • @LoganJones - SQL 注入来自在查询中使用不受信任的用户输入。当您将其作为参数传递时,框架将使其安全。但是,即使是 c# 中的恶意字符串(它可以抵抗buffer overflows 等),通常也是安全的。
  • 太棒了,感谢蒂姆稍后发帖,以确保我得到所有这些正确
猜你喜欢
  • 2011-08-14
  • 1970-01-01
  • 1970-01-01
  • 2017-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-28
  • 1970-01-01
相关资源
最近更新 更多