我听说“所有人”都在使用参数化SQL查询来防止SQL注入攻击,而不必为每一条用户输入提供信息。
你是怎么做到的?使用存储过程时是否自动获得此信息?
所以我理解这是非参数化的:
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
答案 0 :(得分:74)
您的EXEC示例不会参数化。您需要参数化查询(在某些圈子中准备好的语句)以防止这样的输入造成损害:
'; DROP TABLE栏; -
尝试将其放入您的fuz变量中(或者,如果您重视条形表,则不要这样做)。也可能有更微妙和破坏性的查询。
以下是使用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注入。但是,大多数情况下,您仍然需要使用查询参数调用它们,否则它们无法帮助您。如果您使用独占存储过程,那么您可以关闭应用程序用户帐户的SELECT,UPDATE,ALTER,CREATE,DELETE等权限(除了EXEC之外的所有内容)并获得一些保护
答案 1 :(得分:15)
绝对是最后一个,即
或者我是否需要做更广泛的......? (是的,
cmd.Parameters.Add()
)
参数化查询有两个主要优点:
答案 2 :(得分:5)
您想要使用最后一个示例,因为这是唯一真正参数化的示例。除了安全问题(这可能比您想象的要普遍得多)之外,最好让ADO.NET处理参数化,因为您无法确定传入的值是否需要单引号而不检查{{1每个参数。
[编辑]以下是一个例子:
Type
答案 3 :(得分:2)
大多数人都会通过服务器端编程语言库来完成这项工作,例如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*/}
这样可以转义数据以便插入数据库。
一个优点是您可以使用一个准备好的语句多次重复插入,从而获得速度优势。
例如,在上面的查询中,我可以准备一次语句,然后循环从一堆数据创建数据数组,并根据需要重复执行 - >执行多次。
答案 4 :(得分:1)
您的命令文本必须如下:
cmdText = "SELECT foo FROM bar WHERE baz = ?"
cmdText = "EXEC foo_from_baz ?"
然后添加参数值。这种方式确保值con最终仅用作值,而使用另一种方法,如果变量fuz设置为
"x'; delete from foo where 'a' = 'a"
你能看到会发生什么吗?
答案 5 :(得分:0)
这是一个从SQL开始的简短类,您可以从那里构建并添加到类中。
的MySQL
Public Class mysql
'Connection string for mysql
Public SQLSource As String = "Server=123.456.789.123;userid=someuser;password=somesecurepassword;database=somedefaultdatabase;"
'database connection classes
Private DBcon As New MySqlConnection
Private SQLcmd As MySqlCommand
Public DBDA As New MySqlDataAdapter
Public DBDT As New DataTable
Public BindSource As New BindingSource
' parameters
Public Params As New List(Of MySqlParameter)
' some stats
Public RecordCount As Integer
Public Exception As String
Function ExecScalar(SQLQuery As String) As Long
Dim theID As Long
DBcon.ConnectionString = SQLSource
Try
DBcon.Open()
SQLcmd = New MySqlCommand(SQLQuery, DBcon)
'loads params into the query
Params.ForEach(Sub(p) SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value))
'or like this is also good
'For Each p As MySqlParameter In Params
' SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value)
' Next
' clears params
Params.Clear()
'return the Id of the last insert or result of other query
theID = Convert.ToInt32(SQLcmd.ExecuteScalar())
DBcon.Close()
Catch ex As MySqlException
Exception = ex.Message
theID = -1
Finally
DBcon.Dispose()
End Try
ExecScalar = theID
End Function
Sub ExecQuery(SQLQuery As String)
DBcon.ConnectionString = SQLSource
Try
DBcon.Open()
SQLcmd = New MySqlCommand(SQLQuery, DBcon)
'loads params into the query
Params.ForEach(Sub(p) SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value))
'or like this is also good
'For Each p As MySqlParameter In Params
' SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value)
' Next
' clears params
Params.Clear()
DBDA.SelectCommand = SQLcmd
DBDA.Update(DBDT)
DBDA.Fill(DBDT)
BindSource.DataSource = DBDT ' DBDT will contain your database table with your records
DBcon.Close()
Catch ex As MySqlException
Exception = ex.Message
Finally
DBcon.Dispose()
End Try
End Sub
' add parameters to the list
Public Sub AddParam(Name As String, Value As Object)
Dim NewParam As New MySqlParameter(Name, Value)
Params.Add(NewParam)
End Sub
End Class
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