2016-11-03 64 views
0

下面是实现从数据库中获取数据的安全方式的一些代码值的安全呢? 请帮助我,我不了解SQL注入。有人告诉我这段代码很容易被注入。如果是的话,有人可以解释吗?谢谢。返回从数据库(SQL Server和ASP.NET)

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; 
    } 
+1

从这里开始:http://stackoverflow.com/questions/332365/how-does-the-sql-injection-from-the-bobby-tables-xkcd-comic-work – Steve

+0

此代码有很多的错误,并不会甚至运行(你忘了打开连接)。它也暗示连接泄漏 - 'sqlcon'没有被定义,这意味着它是一个没有被清除的字段。它可能不会在其他方法中正常关闭。 –

+0

@Steve谢谢你的链接,这非常有帮助。 –

回答

1

此代码有太多问题。

  • 表,列和条件作为字符串传递并连接,这意味着代码很容易进行SQL注入。
  • 像表,列标准这样的数据库细节被分散到函数的调用者中。你打算使用这种方法来查询Visitor表以外的任何东西吗?
  • 当只需要单个值时使用阅读器。
  • 的连接的using块之外创建并存储在一个字段。 这是definitelly内存泄漏,也可能是连接泄漏。只需在本地创建连接。

一个简单的命令调用修复所有这些问题:

public int CheckIDVisitor(visitorName) 
{ 
    string query = "SELECT ID FROM Visitors where [email protected]"; 
    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 [email protected]"; 
    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; 
    } 
} 

一个更好的办法是使用微型ORM像Dapper.Net摆脱所有这些代码:

public int CheckIDVisitor(visitorName) 
{ 
    using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString)) 
    { 
     string sql = "SELECT ID FROM Visitors WHERE [email protected]" 
     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(); 
    } 
} 
+0

其实我正在使用sql参数来避免注入,但它困扰我,我总是应该写相同的代码。例如,要检查数据库中的某个ID,必须检查ID 1,ID 2和ID 3.我必须三次编写相同的代码结构。但是通过这个示例代码,我只需将必要的东西放在那里,然后只写一个时间码。有没有解决这个问题的建议?或者你也是这样做的 对不起,我忘了更改方法名称hehe。其实这个代码应该包含许多与检查ID有关的事情。 –

+0

发布要执行的* actual *查询。正如你所看到的,事先创建你想要的命令是微不足道的。 –

+0

谢谢你建议我使用类似Dapper.Net的东西。这对我很有帮助(y) –