【问题标题】:The secure way to return some value from database (SQL SERVER & ASP.NET)从数据库返回一些值的安全方法(SQL SERVER & ASP.NET)
【发布时间】:2016-11-03 09:50:52
【问题描述】:

下面的代码是否实现了从数据库中检索数据的安全方式? 请帮助我,我不了解 SQL 注入。有人告诉我这段代码很容易被注入。如果是,有人可以解释一下吗?谢谢。

public int CheckID(string column, string table, string wheres)
    {
        int i = 0;
        sqlcon = ConnectToMain();
        string sqlquery = "SELECT "+column+" FROM "+table+" "+wheres+"";
        using (sqlcon)
        {
            sqlcon.Open();
            SqlCommand sqlcom = new SqlCommand(sqlquery, sqlcon);
            using (sqlcom)
            {
                SqlDataReader dr = sqlcom.ExecuteReader();
                dr.Read();
                if (dr.HasRows)
                {
                    i = dr.GetInt32(0);
                }
                else
                {
                    i = 0;
                }
            }
            sqlcon.Close();
        }
        return i;
    }

【问题讨论】:

  • 这段代码有很多错误,甚至无法运行(您忘记打开连接)。它还暗示连接泄漏 - sqlcon 未定义,这意味着它是一个未清除的字段。它可能也不会在其他方法中正确关闭。
  • @Steve 谢谢你的链接,它很有帮助。
  • @PanagiotisKanavos “你忘记打开连接”是什么意思?
  • 我在噪音中错过了Open()。这个 sn-p 实际上对于可重用性更差。你最终传递了不必要的参数——你真的要搜索用户表吗?还是付款?您要执行的实际查询是什么?如果要搜索 ID 列表,请使用 IN (1,2,3) 子句。或者使用 EF 或像 Dapper 这样的微型 ORM 来避免这一切。

标签: c# asp.net wcf


【解决方案1】:

这段代码有太多问题。

  • 表、列和条件作为字符串传递并连接在一起,这意味着代码容易发生SQL注入。
  • 表、列标准等数据库详细信息会溢出到函数的调用者中。您是否打算使用此方法查询除访问者表之外的任何内容?
  • 当只需要一个值时使用读取器。
  • 连接在using 块外创建并存储在字段中。 这绝对是内存泄漏,也可能是连接泄漏。只需在本地创建连接。

一个简单的命令调用解决了所有这些问题:

public int CheckIDVisitor(visitorName)
{
    string query = "SELECT ID FROM Visitors where Name=@name";
    using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
    using( var cmd=new SqlCommand(query,sqlConn))
    {
        var cmdParam=cmd.Parameters.Add("@name",SqlDbType.NVarChar,20);
        cmdParam.Value=visitorName;
        sqlConn.Open();

        var result=(int?)cmd.ExecuteScalar();
        return result??0;
    }
}

您也可以提前创建命令并将其存储在字段中。您可以在每次要执行时将连接附加到命令:

public void InitVisitorCommand()
{
    string query = "SELECT ID FROM Visitors where Name=@name";
    var cmd=new SqlCommand(query,sqlConn);
    var cmdParam=cmd.Parameters.Add("@name",SqlDbType.NVarChar,20);
    _myVisitorCommand=cmd;
}

...

public int CheckIDVisitor(visitorName)
{
    using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
    {
        _myVisitorCommand.Parameters.["@name"]Value=visitorName;
        _myVisitorCommand.Connection=sqlConn;
        sqlConn.Open();

        var result=(int?)cmd.ExecuteScalar();
        return result??0;
    }
}

更好的选择是使用像 Dapper.Net 这样的微 ORM 来摆脱所有这些代码:

public int CheckIDVisitor(visitorName)
{
    using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
    {
        string sql = "SELECT ID FROM Visitors WHERE name=@name"
        var result = conn.Query<int?>(sql, new { name = visitorName);
        return result??0;
    }
}

或者

public int[] CheckIDVisitors(string []visitors)
{
    using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
    {
        string sql = "SELECT ID FROM Visitors WHERE name IN @names"
        var results = conn.Query<int?>(sql, new { names = visitors);
        return results.ToArray();
    }
}

【讨论】:

  • 实际上我使用 sql 参数来避免这种注入,但它困扰着我,我总是应该编写相同的代码。例如,要检查数据库中的某个 ID,我必须检查 ID 1、ID 2 和 ID 3。并且我必须编写相同结构的代码 3 次。但是对于那个示例代码,我只是把必要的东西放在那里,然后只写一次代码。有什么建议可以解决这个问题吗?或者你也在做同样的事情对不起我的不好,我忘了更改方法名称嘿嘿。其实这段代码应该涵盖了很多和查ID相关的东西。
  • 发布您要执行的实际查询。如您所见,提前创建您想要的命令是微不足道的。
  • 感谢您建议我使用像 Dapper.Net 这样的东西。这对我很有帮助(y)
猜你喜欢
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多