参数绑定:幕后将发生什么?
时间:2020-03-05 18:40:27 来源:igfitidea点击:
.NET,Java和其他各种语言的高级数据库API经常提供称为准备语句和参数绑定的技术,而不是将纯文本命令发送到数据库服务器。我想知道的是,当我们执行如下语句时会发生什么:
SqlCommand cmd = new SqlCommand("GetMemberByID"); cmd.CommandType = CommandType.StoredProcedure; SqlParameter param = new SqlParameter("@ID", memberID); para.DbType = DbType.Integer; cmd.Parameters.Add(param);
我知道这是最佳做法。这样可以最大程度地减少SQL注入攻击。但是,当我们执行这些语句时,到底发生了什么?最终结果仍然是SQL安全字符串吗?如果没有,最终结果是什么?这足以防止SQL注入攻击吗?
解决方案
回答
有关准备好的语句的MySQL手册页提供了很多信息(这些信息应适用于任何其他RDBMS)。
基本上,语句是提前解析和处理的,参数是单独发送的,而不是与SQL代码一起处理。这消除了SQL注入攻击,因为甚至在设置参数之前就已对SQL进行了解析。
回答
如果我们使用的是MS SQL,请加载分析器,然后我们将看到使用参数化查询时生成的SQL语句。这是针对SQL Server 2005的示例(我使用的是Enterprise Libary 3.1,但直接使用SqlParameters的结果是相同的):
string sql = "SELECT * FROM tblDomains WHERE DomainName = @DomName AND DomainID = @Did"; Database db = DatabaseFactory.CreateDatabase(); using(DbCommand cmd = db.GetSqlStringCommand(sql)) { db.AddInParameter(cmd, "DomName", DbType.String, "xxxxx.net"); db.AddInParameter(cmd, "Did", DbType.Int32, 500204); DataSet ds = db.ExecuteDataSet(cmd); }
这将产生:
exec sp[underscore]executesql N'SELECT * FROM tblDomains WHERE DomainName = @DomName AND DomainID = @Did', N'@DomName nvarchar(9), @Did int', @DomName=N'xxxxx.net', @Did=500204
我们还可以在这里看到,如果引号字符作为参数传递,则它们将相应地转义:
db.AddInParameter(cmd, "DomName", DbType.String, "'xxxxx.net"); exec sp[underscore]executesql N'SELECT * FROM tblDomains WHERE DomainName = @DomName AND DomainID = @Did', N'@DomName nvarchar(10), @Did int', @DomName=N'''xxxxx.net', @Did=500204
回答
用外行术语来说:如果发送了一条准备好的语句,那么数据库将使用一个计划(如果有的话),它不必每次发送此查询时都重新创建计划,而只需更改参数的值。这与proc的工作方式非常相似,proc的另一个好处是我们可以仅通过proc授予权限,而根本不授予底层表的权限