如何创建参数化SQL查询?我为什么要这样做?
我听说“每个人”都在使用参数化SQL查询来防止SQL注入攻击,而不必利用每一条用户输入 你是怎么做到的?在使用存储过程时是否会自动获取此信息 所以我的理解是,这是非参数化的:如何创建参数化SQL查询?我为什么要这样做?,sql,vb.net,sql-parametrized-query,Sql,Vb.net,Sql Parametrized Query,我听说“每个人”都在使用参数化SQL查询来防止SQL注入攻击,而不必利用每一条用户输入 你是怎么做到的?在使用存储过程时是否会自动获取此信息 所以我的理解是,这是非参数化的: cmdText=String.Format(“从baz='{0}',fuz的条形图中选择foo) 这是参数化的吗 cmdText=String.Format(“EXEC foo_from_baz'{0}',fuz) 或者我需要做一些更广泛的事情来保护自己不受SQL注入的影响吗 With命令 .Parameters.Co
cmdText=String.Format(“从baz='{0}',fuz的条形图中选择foo)
这是参数化的吗
cmdText=String.Format(“EXEC foo_from_baz'{0}',fuz)
或者我需要做一些更广泛的事情来保护自己不受SQL注入的影响吗
With命令
.Parameters.Count=1
.Parameters.Item(0).ParameterName=“@baz”
.参数.项目(0).值=引信
以
除了安全考虑之外,使用参数化查询还有其他好处吗
更新:这篇伟大的文章链接在Grotok的一个问题参考中。
您想继续上一个示例,因为这是唯一一个真正参数化的示例。除了安全问题(可能比您想象的要普遍得多),最好让ADO.NET处理参数化,因为如果不检查每个参数的
类型
,您无法确定要传递的值是否需要单引号
[编辑]以下是一个示例:
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);
您的EXEC示例将不会参数化。您需要参数化查询(某些圆圈中的准备语句)来防止这样的输入造成损害: ",;升降台杆-- 尝试将其放入fuz变量中(或者,如果您对bar表进行了估值,则不要这样做)。还有可能出现更微妙、更具破坏性的查询 以下是如何使用Sql Server执行参数的示例:
公共函数GetBarFooByBaz(ByVal Baz作为字符串)作为字符串
Dim sql As String=“从baz=@baz的栏中选择foo”
将cn用作新的SqlConnection(“此处为您的连接字符串”)_
cmd作为新的SqlCommand(sql,cn)
cmd.Parameters.Add(“@Baz”,SqlDbType.VarChar,50)。Value=Baz
返回cmd.ExecuteScalar().ToString()
终端使用
端函数
存储过程有时被认为是阻止SQL注入的原因。但是,大多数情况下,您仍然必须使用查询参数调用它们,否则它们就没有帮助了。如果专门使用存储过程,则可以关闭应用程序用户帐户的选择、更新、更改、创建、删除等权限(除EXEC外的所有权限),并通过这种方式获得一些保护。您的命令文本需要如下所示:
cmdText = "SELECT foo FROM bar WHERE baz = ?"
cmdText = "EXEC foo_from_baz ?"
然后添加参数值。这种方法确保值con仅最终用作值,而如果变量fuz设置为
"x'; delete from foo where 'a' = 'a"
你能看到会发生什么吗?大多数人都会通过服务器端编程语言库来实现这一点,比如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*/}
这负责转义数据以插入数据库
一个优点是,您可以使用一条准备好的语句多次重复插入,从而获得速度优势
例如,在上面的查询中,我可以准备一次语句,然后从一堆数据循环创建数据数组,并根据需要重复->执行多次。肯定是最后一次,即 还是我需要做一些更广泛的。。。?(是,
cmd.Parameters.Add()
)
参数化查询有两个主要优点:
- 安全性:这是避免漏洞的好方法
- 性能:如果您经常使用不同的参数调用同一查询,那么参数化查询可能会允许数据库缓存您的查询,这是性能提高的一个重要来源
- 额外:您不必担心数据库代码中的日期和时间格式问题。类似地,如果您的代码将在非英语语言环境的计算机上运行,那么小数点/小数逗号将不会出现问题
- 这里有一个简短的类,从SQL开始,您可以在此基础上构建并添加到该类中
MySQL
MS SQL/Express
Public Class MSSQLDB
' CREATE YOUR DB CONNECTION
'Change the datasource
Public SQLSource As String = "Data Source=someserver\sqlexpress;Integrated Security=True"
Private DBCon As New SqlConnection(SQLSource)
' PREPARE DB COMMAND
Private DBCmd As SqlCommand
' DB DATA
Public DBDA As SqlDataAdapter
Public DBDT As DataTable
' QUERY PARAMETERS
Public Params As New List(Of SqlParameter)
' QUERY STATISTICS
Public RecordCount As Integer
Public Exception As String
Public Sub ExecQuery(Query As String, Optional ByVal RunScalar As Boolean = False, Optional ByRef NewID As Long = -1)
' RESET QUERY STATS
RecordCount = 0
Exception = ""
Dim RunScalar As Boolean = False
Try
' OPEN A CONNECTION
DBCon.Open()
' CREATE DB COMMAND
DBCmd = New SqlCommand(Query, DBCon)
' LOAD PARAMS INTO DB COMMAND
Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))
' CLEAR PARAMS LIST
Params.Clear()
' EXECUTE COMMAND & FILL DATATABLE
If RunScalar = True Then
NewID = DBCmd.ExecuteScalar()
End If
DBDT = New DataTable
DBDA = New SqlDataAdapter(DBCmd)
RecordCount = DBDA.Fill(DBDT)
Catch ex As Exception
Exception = ex.Message
End Try
' CLOSE YOUR CONNECTION
If DBCon.State = ConnectionState.Open Then DBCon.Close()
End Sub
' INCLUDE QUERY & COMMAND PARAMETERS
Public Sub AddParam(Name As String, Value As Object)
Dim NewParam As New SqlParameter(Name, Value)
Params.Add(NewParam)
End Sub
End Class
我觉得很震惊,很明显这个问题以前没有在Stackoverflow上被问过。非常好!哦,是的。当然,措辞非常不同,但它确实如此。您应该使用参数化查询来防止破坏数据。无法抗拒:)With块有什么不好?是否有人有问题#关于“With块有什么不好”的问题?请注意:。Net字符串是unicode,因此默认情况下参数将采用NVarChar。如果它真的是一个VarChar列,这可能会导致很大的性能问题。你能进一步解释一下这个
cmd.Parameters.Add(“@Baz”,SqlDbType.VarChar,50)。Value=Baz
请?@CaryBondoc,你想知道什么?该行创建了一个名为@Baz
的参数,该参数的类型为varchar(50)
,它被分配了Baz
字符串的值。您也可以说“command.parameters.addithValue(@Baz,50)”@GavinPerkins假设您的意思是AddWithValue(@Baz,Baz)
,您可以这样做,特别是因为将默认映射为nvarchar
的字符串值转换为实际的varchar
类型是可以触发该链接中提到的效果的最常见位置之一。
Public Class MSSQLDB
' CREATE YOUR DB CONNECTION
'Change the datasource
Public SQLSource As String = "Data Source=someserver\sqlexpress;Integrated Security=True"
Private DBCon As New SqlConnection(SQLSource)
' PREPARE DB COMMAND
Private DBCmd As SqlCommand
' DB DATA
Public DBDA As SqlDataAdapter
Public DBDT As DataTable
' QUERY PARAMETERS
Public Params As New List(Of SqlParameter)
' QUERY STATISTICS
Public RecordCount As Integer
Public Exception As String
Public Sub ExecQuery(Query As String, Optional ByVal RunScalar As Boolean = False, Optional ByRef NewID As Long = -1)
' RESET QUERY STATS
RecordCount = 0
Exception = ""
Dim RunScalar As Boolean = False
Try
' OPEN A CONNECTION
DBCon.Open()
' CREATE DB COMMAND
DBCmd = New SqlCommand(Query, DBCon)
' LOAD PARAMS INTO DB COMMAND
Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))
' CLEAR PARAMS LIST
Params.Clear()
' EXECUTE COMMAND & FILL DATATABLE
If RunScalar = True Then
NewID = DBCmd.ExecuteScalar()
End If
DBDT = New DataTable
DBDA = New SqlDataAdapter(DBCmd)
RecordCount = DBDA.Fill(DBDT)
Catch ex As Exception
Exception = ex.Message
End Try
' CLOSE YOUR CONNECTION
If DBCon.State = ConnectionState.Open Then DBCon.Close()
End Sub
' INCLUDE QUERY & COMMAND PARAMETERS
Public Sub AddParam(Name As String, Value As Object)
Dim NewParam As New SqlParameter(Name, Value)
Params.Add(NewParam)
End Sub
End Class