参数化 SQL 查询

Posted

技术标签:

【中文标题】参数化 SQL 查询【英文标题】:Parameterize SQL Queries 【发布时间】:2019-08-20 09:45:29 【问题描述】:

我想参数化一些 SQL 语句,这样我的代码就不再受 SQL 注入的影响但我实际上没有计划如何参数化例如 where 子句。

Dim accID As String = DatabaseConnecter.readField("SELECT ID FROM accounts WHERE accountname ='" & user & "' AND password='" & pw & "';")

问题是如果您输入给定的用户名,例如测试和扩展用户名。您无需在应用程序中输入密码即可登录。

编辑:

Public Function readField(ByVal sql As String) As String
        Dim output As String = "ERROR"
        Using cn = New mysqlConnection(connString.ToString())
            Using cmd = New MySqlCommand(sql, cn)
                cn.Open()
                Using rd = cmd.ExecuteReader()
                    Try
                        rd.Read()
                        output = rd.GetString(0)
                        rd.Close()
                    Catch ex As Exception
                    End Try
                End Using
                cn.Close()
            End Using
        End Using
        Return output
    End Function
´´´

【问题讨论】:

如果您想参数化该查询,您需要更改 readField 方法。你能把readField的代码贴出来吗? @Steve Done。我希望你现在可以帮助我:) 【参考方案1】:

要进行参数化查询,您需要创建参数并编写适当的 SQL 文本,其中您可以使用参数占位符代替直接从用户键入的值。

例如,你的sql文本应该是这样的

Dim sqlText = "SELECT ID FROM accounts WHERE accountname =@name AND password=@pwd"

现在你有了一个参数化的文本,但我们仍然需要创建将与你的 sql 命令一起发送到数据库引擎的参数。

在调用执行查询的方法之前,可以通过这种方式创建参数(本例中为两个)

Dim p1 as MySqlParameter = new MySqlParameter("@name", MySqlDbType.VarChar)
p1.Value = user  

Dim p2 as MySqlParameter = new MySqlParameter("@pwd", MySqlDbType.VarChar)
p2.Value = password

Dim pms As List(Of MySqlParameter) = new List(Of MySqlParameter)()
pms.Add(p1)
pms.Add(p2)

现在我们需要将此列表传递给您的方法(这需要更改您的方法签名)

DatabaseConnecter.readField(sqlText, pms)

方法本身应该变成类似

Public Function readField(ByVal sql As String, Optional pms As List(Of MySqlParameter) = Nothing) As String
    Dim output As String = "ERROR"
    Using cn = New MySqlConnection(connString.ToString())
        Using cmd = New MySqlCommand(sql, cn)
            cn.Open()

            ' This block adds the parameter defined by the caller to the command
            ' The parameters are optional so we need to check if we have really received the list or not
            if pms IsNot Nothing Then
                cmd.Parameters.AddRange(pms.ToArray())
            End If
            Using rd = cmd.ExecuteReader()
                Try
                    rd.Read()
                    output = rd.GetString(0)
                    rd.Close()
                Catch ex As Exception
                End Try
            End Using
            ' no need to close when inside a using block
            ' cn.Close()
        End Using
    End Using
    Return output
End Function

该方法现在有一个可选参数,它将包含查询所需的参数列表(如果您的查询不需要参数,则不包含任何参数)。该列表被添加到命令参数集合中,现在执行查询。

最后提示:以明文形式将密码存储到数据库中是一个众所周知的安全问题。建议你搜索一下how to store passwords in a database.

【讨论】:

【参考方案2】:
Private Function GetID(User As String, pw As String) As String
    Using cmd As New SqlCommand("SELECT ID FROM accounts WHERE accountname =@user AND password=@password", New SqlConnection(SQLConnString))
        cmd.Parameters.AddWithValue("@user", User)
        cmd.Parameters.Add("@password", SqlDbType.NVarChar)
        cmd.Parameters("@password").Value = pw
        Try
            cmd.Connection.Open()
            Return cmd.ExecuteScalar()
        Catch ex As Exception
            'handle error
            Return Nothing
        Finally
            cmd.Connection.Close()
        End Try
    End Using

End Function

我已经演示了两种设置参数的方法。搜索更多信息或比较。

【讨论】:

我使用 Mysql.data 因为我连接到 MariaDB 而不是 MS SQL DB 我相信 MySql 的语法是相似的。此链接可能对dev.mysql.com/doc/dev/connector-net/8.0/html/… 有所帮助

以上是关于参数化 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

参数化 SQL 查询

这个参数化查询如何防止 SQL 注入?

mybatis的sql参数化查询

Sql Server参数化查询之where in和like实现详解

Sql Server参数化查询之where in和like实现详解

参数化查询如何帮助防止 SQL 注入?