我如何创build一个参数化的SQL查询? 我为什么要?

我听说“每个人”都在使用参数化的SQL查询来防止SQL注入攻击,而不必为每一个用户input提供警报。

你怎么做到这一点? 你使用存储过程时会自动得到这个吗?

所以我的理解是非参数化的:

cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz) 

这将参数化?

 cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz) 

还是我需要做这样更广泛的事情,以保护自己免受SQL注入?

 With command .Parameters.Count = 1 .Parameters.Item(0).ParameterName = "@baz" .Parameters.Item(0).Value = fuz End With 

使用参数化查询还有其他好处,除了安全考虑?

更新:这个伟大的文章被链接在Grotok的一个问题引用。 http://www.sommarskog.se/dynamic_sql.html

你的EXEC例子不会被参数化。 你需要参数化的查询(在一些圈子里准备好的语句)来防止这样的input造成损害:

'; DROP TABLE bar; –

尝试把它放在你的fuzvariables中(或者,如果你重视你的酒吧表)。 更细微和破坏性的查询也是可能的。

下面是一个如何使用Sql Server做参数的例子:

 Public Function GetBarFooByBaz(ByVal Baz As String) As String Dim sql As String = "SELECT foo FROM bar WHERE baz= @Baz" Using cn As New SqlConnection("Your connection string here"), _ cmd As New SqlCommand(sql, cn) cmd.Parameters.Add("@Baz", SqlDbType.VarChar, 50).Value = Baz Return cmd.ExecuteScalar().ToString() End Using End Function 

存储过程有时用于防止SQL注入。 但是,大多数情况下,您仍然需要使用查询参数来调用它们,否则他们不会提供帮助。 如果您独占使用存储过程,那么您可以closures对应用程序用户帐户的SELECT,UPDATE,ALTER,CREATE,DELETE等权限(几乎所有除EXEC),并获得一些保护方式。

绝对是第二个。

参数化查询有两个主要优点:

  • 安全性:这是避免SQL注入漏洞的好方法
  • 性能:如果您经常使用不同的参数调用相同的查询,则参数化查询可能允许数据库caching查询,这是性能提升的重要来源。
  • 额外:您不必担心数据库代码中的date和时间格式问题。 同样,如果您的代码将永远在非英语语言环境的机器上运行,您将不会有小数点/小数逗号问题。

你想和你的最后一个例子一起,因为这是唯一真正参数化的例子。 除了安全方面的担忧之外(你可能会认为这更为普遍),最好让ADO.NET处理参数化,因为你不能确定你传入的值是否需要单引号,而不检查每个Type参数。

[编辑]这里是一个例子:

 SqlCommand command = new SqlCommand( "select foo from bar where baz = @baz", yourSqlConnection ); SqlParameter parameter = new SqlParameter(); parameter.ParameterName = "@baz"; parameter.Value = "xyz"; command.Parameters.Add(parameter); 

大多数人会通过服务器端编程语言库,如PHP的PDO或Perl DBI来做到这一点。

例如,在PDO中:

 $dbh=pdo_connect(); //you need a connection function, returns a pdo db connection $sql='insert into squip values(null,?,?)'; $statement=$dbh->prepare($sql); $data=array('my user supplied data','more stuff'); $statement->execute($data); if($statement->rowCount()==1){/*it worked*/} 

这样可以避免数据库插入的数据。

一个好处是你可以用一个准备好的语句多次重复插入,获得速度优势。

例如,在上面的查询中,我可以准备一次语句,然后从一堆数据中循环创build数据数组,并根据需要重复 – >执行多次。

你的命令文本需要像:

 cmdText = "SELECT foo FROM bar WHERE baz = ?" cmdText = "EXEC foo_from_baz ?" 

然后添加参数值。 这样可以确保值con只能用作一个值,而用另一种方法如果variablesfuz被设置为

 "x'; delete from foo where 'a' = 'a" 

你能看到会发生什么?